@assistant-ui/react-ai-sdk 1.3.32 → 1.3.35
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/client.d.ts +9 -0
- package/dist/client.js +8 -0
- package/dist/frontendTools.d.ts +1 -1
- package/dist/frontendTools.js.map +1 -1
- package/dist/generativeTools.d.ts +18 -4
- package/dist/generativeTools.d.ts.map +1 -1
- package/dist/generativeTools.js +14 -5
- package/dist/generativeTools.js.map +1 -1
- package/dist/index.d.ts +3 -4
- package/dist/index.js +3 -4
- package/dist/index.native.d.ts +9 -0
- package/dist/index.native.js +8 -0
- package/dist/injectQuoteContext.js.map +1 -1
- package/dist/mcp-stdio.node.d.ts +2 -0
- package/dist/mcp-stdio.node.js +2 -0
- package/dist/mcp-stdio.unsupported.d.ts +7 -0
- package/dist/mcp-stdio.unsupported.d.ts.map +1 -0
- package/dist/mcp-stdio.unsupported.js +11 -0
- package/dist/mcp-stdio.unsupported.js.map +1 -0
- package/dist/modelContentEnvelope.d.ts +2 -1
- package/dist/modelContentEnvelope.d.ts.map +1 -1
- package/dist/toolOutputConversion.d.ts +1 -1
- package/dist/ui/resumable.d.ts +2 -1
- package/dist/ui/resumable.d.ts.map +1 -1
- package/dist/ui/resumable.js +1 -1
- package/dist/ui/use-chat/AssistantChatTransport.js +2 -2
- package/dist/ui/use-chat/AssistantChatTransport.js.map +1 -1
- package/dist/ui/use-chat/useAISDKRuntime.d.ts +10 -0
- package/dist/ui/use-chat/useAISDKRuntime.d.ts.map +1 -1
- package/dist/ui/use-chat/useAISDKRuntime.js +13 -4
- package/dist/ui/use-chat/useAISDKRuntime.js.map +1 -1
- package/dist/ui/use-chat/useChatRuntime.d.ts +1 -0
- package/dist/ui/use-chat/useChatRuntime.d.ts.map +1 -1
- package/dist/ui/use-chat/useChatRuntime.js +3 -2
- package/dist/ui/use-chat/useChatRuntime.js.map +1 -1
- package/dist/ui/use-chat/useExternalHistory.d.ts +4 -1
- package/dist/ui/use-chat/useExternalHistory.d.ts.map +1 -1
- package/dist/ui/use-chat/useExternalHistory.js +25 -1
- package/dist/ui/use-chat/useExternalHistory.js.map +1 -1
- package/dist/ui/use-chat/useStreamingTiming.js +1 -1
- package/dist/ui/utils/convertMessage.d.ts +2 -2
- package/dist/ui/utils/convertMessage.d.ts.map +1 -1
- package/dist/ui/utils/convertMessage.js +5 -2
- package/dist/ui/utils/convertMessage.js.map +1 -1
- package/dist/ui/utils/sliceMessagesUntil.js.map +1 -1
- package/dist/ui/utils/toCreateMessage.js.map +1 -1
- package/dist/usage.js.map +1 -1
- package/package.json +28 -12
- package/src/client.ts +18 -0
- package/src/generativeTools.test.ts +29 -47
- package/src/generativeTools.ts +18 -4
- package/src/index.native.ts +3 -0
- package/src/index.ts +1 -16
- package/src/mcp-stdio.node.ts +1 -0
- package/src/mcp-stdio.unsupported.ts +12 -0
- package/src/ui/use-chat/useAISDKRuntime.test.ts +104 -1
- package/src/ui/use-chat/useAISDKRuntime.ts +31 -1
- package/src/ui/use-chat/useChatRuntime.ts +3 -0
- package/src/ui/use-chat/useExternalHistory.ts +30 -1
- package/src/ui/utils/convertMessage.test.ts +36 -5
- package/src/ui/utils/convertMessage.ts +9 -1
- package/dist/assistant-stream/dist/core/AssistantStream.d.ts +0 -1
- package/dist/assistant-stream/dist/core/AssistantStreamChunk.d.ts +0 -1
- package/dist/assistant-stream/dist/core/accumulators/AssistantMessageStream.d.ts +0 -1
- package/dist/assistant-stream/dist/core/accumulators/assistant-message-accumulator.d.ts +0 -1
- package/dist/assistant-stream/dist/core/modules/assistant-stream.d.ts +0 -1
- package/dist/assistant-stream/dist/core/modules/text.d.ts +0 -1
- package/dist/assistant-stream/dist/core/modules/tool-call.d.ts +0 -1
- package/dist/assistant-stream/dist/core/serialization/PlainText.d.ts +0 -1
- package/dist/assistant-stream/dist/core/serialization/assistant-transport/AssistantTransport.d.ts +0 -1
- package/dist/assistant-stream/dist/core/serialization/data-stream/DataStream.d.ts +0 -1
- package/dist/assistant-stream/dist/core/serialization/ui-message-stream/UIMessageStream.d.ts +0 -1
- package/dist/assistant-stream/dist/core/tool/ToolExecutionStream.d.ts +0 -1
- package/dist/assistant-stream/dist/core/tool/schema-utils.d.ts +0 -15
- package/dist/assistant-stream/dist/core/tool/schema-utils.d.ts.map +0 -1
- package/dist/assistant-stream/dist/core/tool/schema-utils.js +0 -59
- package/dist/assistant-stream/dist/core/tool/schema-utils.js.map +0 -1
- package/dist/assistant-stream/dist/core/tool/tool-types.d.ts +0 -69
- package/dist/assistant-stream/dist/core/tool/tool-types.d.ts.map +0 -1
- package/dist/assistant-stream/dist/core/tool/toolResultStream.d.ts +0 -1
- package/dist/assistant-stream/dist/core/utils/stream/AssistantMetaTransformStream.d.ts +0 -1
- package/dist/assistant-stream/dist/core/utils/stream/AssistantTransformStream.d.ts +0 -1
- package/dist/assistant-stream/dist/core/utils/types.d.ts +0 -1
- package/dist/assistant-stream/dist/index.d.ts +0 -2
- package/dist/assistant-stream/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts +0 -140
- package/dist/assistant-stream/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts.map +0 -1
- package/dist/assistant-stream/dist/resumable/createResumableAssistantStreamResponse.d.ts +0 -6
- package/dist/assistant-stream/dist/resumable/createResumableAssistantStreamResponse.d.ts.map +0 -1
- package/dist/assistant-stream/dist/resumable/createResumableAssistantStreamResponse.js +0 -6
- package/dist/assistant-stream/dist/resumable/createResumableAssistantStreamResponse.js.map +0 -1
- package/dist/assistant-stream/dist/resumable/index.d.ts +0 -1
- package/dist/assistant-stream/dist/utils/json/json-value.d.ts +0 -10
- package/dist/assistant-stream/dist/utils/json/json-value.d.ts.map +0 -1
- package/dist/assistant-stream/dist/utils.d.ts +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChatRuntime.d.ts","names":[],"sources":["../../../src/ui/use-chat/useChatRuntime.ts"],"mappings":";;;;;;;KAwBY,qBAAA,oBAAyC,WAAA,GAAY,WAAA,IAC/D,QAAA,CAAS,UAAA,IACP,0BAAA;EACE,KAAA,GAAQ,cAAA;EACR,QAAA,GAAW,mBAAA;EACX,eAAA,GAAkB,6BAAA;EAClB,QAAA,GAAW,mBAAA;AAAA;AAAA,
|
|
1
|
+
{"version":3,"file":"useChatRuntime.d.ts","names":[],"sources":["../../../src/ui/use-chat/useChatRuntime.ts"],"mappings":";;;;;;;KAwBY,qBAAA,oBAAyC,WAAA,GAAY,WAAA,IAC/D,QAAA,CAAS,UAAA,IACP,0BAAA;EACE,KAAA,GAAQ,cAAA;EACR,QAAA,GAAW,mBAAA;EACX,eAAA,GAAkB,6BAAA;EAClB,QAAA,GAAW,mBAAA;EACX,YAAA,GAAe,mBAAA;AAAA;AAAA,cA0GR,cAAA,sBAAqC,WAAA,GAAY,WAAA;EAAW,KAAA;EAAA,GAAA;AAAA,IAGtE,qBAAA,CAAsB,UAAA,MAAmB,gBAAA"}
|
|
@@ -24,7 +24,7 @@ const getResumableAdapter = (transport) => {
|
|
|
24
24
|
return candidate.call(transport);
|
|
25
25
|
};
|
|
26
26
|
const useChatThreadRuntime = (options) => {
|
|
27
|
-
const { adapters, transport: transportOptions, toCreateMessage, isDisabled: _isDisabled, isSendDisabled: _isSendDisabled, unstable_capabilities: _unstable_capabilities, suggestions: _suggestions, onResume, ...chatOptions } = options ?? {};
|
|
27
|
+
const { adapters, transport: transportOptions, toCreateMessage, isDisabled: _isDisabled, isSendDisabled: _isSendDisabled, unstable_capabilities: _unstable_capabilities, suggestions: _suggestions, onResume, joinStrategy, ...chatOptions } = options ?? {};
|
|
28
28
|
const transport = useDynamicChatTransport(transportOptions ?? new AssistantChatTransport());
|
|
29
29
|
const id = useAuiState((s) => s.threadListItem.id);
|
|
30
30
|
const aui = useAui();
|
|
@@ -37,7 +37,8 @@ const useChatThreadRuntime = (options) => {
|
|
|
37
37
|
adapters,
|
|
38
38
|
...pickExternalStoreSharedOptions(options ?? {}),
|
|
39
39
|
...toCreateMessage && { toCreateMessage },
|
|
40
|
-
...onResume && { onResume }
|
|
40
|
+
...onResume && { onResume },
|
|
41
|
+
...joinStrategy && { joinStrategy }
|
|
41
42
|
});
|
|
42
43
|
if (transport instanceof AssistantChatTransport) {
|
|
43
44
|
transport.setRuntime(runtime);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChatRuntime.js","names":[],"sources":["../../../src/ui/use-chat/useChatRuntime.ts"],"sourcesContent":["\"use client\";\n\nimport { useChat, type UIMessage } from \"@ai-sdk/react\";\nimport type { AssistantCloud } from \"assistant-cloud\";\nimport {\n pickExternalStoreSharedOptions,\n type AssistantRuntime,\n type ExternalStoreSharedOptions,\n} from \"@assistant-ui/core\";\nimport {\n useCloudThreadListAdapter,\n useRemoteThreadListRuntime,\n} from \"@assistant-ui/core/react\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport {\n useAISDKRuntime,\n type AISDKRuntimeAdapter,\n type CustomToCreateMessageFunction,\n} from \"./useAISDKRuntime\";\nimport type { ChatInit, ChatTransport } from \"ai\";\nimport { AssistantChatTransport } from \"./AssistantChatTransport\";\nimport type { AssistantChatResumableOptions } from \"../resumable\";\nimport { useEffect, useMemo, useRef } from \"react\";\n\nexport type UseChatRuntimeOptions<UI_MESSAGE extends UIMessage = UIMessage> =\n ChatInit<UI_MESSAGE> &\n ExternalStoreSharedOptions & {\n cloud?: AssistantCloud | undefined;\n adapters?: AISDKRuntimeAdapter[\"adapters\"] | undefined;\n toCreateMessage?: CustomToCreateMessageFunction;\n onResume?: AISDKRuntimeAdapter[\"onResume\"];\n };\n\nconst useDynamicChatTransport = <UI_MESSAGE extends UIMessage = UIMessage>(\n transport: ChatTransport<UI_MESSAGE>,\n): ChatTransport<UI_MESSAGE> => {\n const transportRef = useRef<ChatTransport<UI_MESSAGE>>(transport);\n useEffect(() => {\n transportRef.current = transport;\n });\n const dynamicTransport = useMemo(\n () =>\n new Proxy(transportRef.current, {\n get(_, prop) {\n const res =\n transportRef.current[prop as keyof ChatTransport<UI_MESSAGE>];\n return typeof res === \"function\"\n ? res.bind(transportRef.current)\n : res;\n },\n }),\n [],\n );\n return dynamicTransport;\n};\n\nconst getResumableAdapter = <UI_MESSAGE extends UIMessage>(\n transport: ChatTransport<UI_MESSAGE>,\n): AssistantChatResumableOptions | undefined => {\n if (transport instanceof AssistantChatTransport) {\n return transport.getResumableAdapter();\n }\n const candidate = (transport as { getResumableAdapter?: () => unknown })\n .getResumableAdapter;\n if (typeof candidate !== \"function\") return undefined;\n return candidate.call(transport) as AssistantChatResumableOptions | undefined;\n};\n\nconst useChatThreadRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(\n options?: UseChatRuntimeOptions<UI_MESSAGE>,\n): AssistantRuntime => {\n const {\n adapters,\n transport: transportOptions,\n toCreateMessage,\n isDisabled: _isDisabled,\n isSendDisabled: _isSendDisabled,\n unstable_capabilities: _unstable_capabilities,\n suggestions: _suggestions,\n onResume,\n ...chatOptions\n } = options ?? {};\n // peel guard: any shared key left in `chatOptions` collapses this to `never`\n true satisfies keyof typeof chatOptions &\n keyof ExternalStoreSharedOptions extends never\n ? true\n : never;\n\n const transport = useDynamicChatTransport(\n transportOptions ?? new AssistantChatTransport(),\n );\n\n const id = useAuiState((s) => s.threadListItem.id);\n const aui = useAui();\n const chat = useChat({\n ...chatOptions,\n id,\n transport,\n });\n\n const runtime = useAISDKRuntime(chat, {\n adapters,\n ...pickExternalStoreSharedOptions(options ?? {}),\n ...(toCreateMessage && { toCreateMessage }),\n ...(onResume && { onResume }),\n });\n\n if (transport instanceof AssistantChatTransport) {\n transport.setRuntime(runtime);\n transport.__internal_setGetThreadListItem(() =>\n aui.threadListItem.source ? aui.threadListItem() : undefined,\n );\n }\n\n const resumeFiredRef = useRef(false);\n useEffect(() => {\n if (resumeFiredRef.current) return;\n const adapter = getResumableAdapter(transport);\n if (!adapter) return;\n const pending = adapter.storage.getStreamId();\n if (!pending) return;\n resumeFiredRef.current = true;\n chat.resumeStream().catch((err: unknown) => {\n console.warn(\n \"[assistant-ui] resumable: resume failed; clearing stored stream id\",\n err,\n );\n adapter.storage.clear();\n });\n }, [transport, chat]);\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 = useCloudThreadListAdapter({ cloud });\n return useRemoteThreadListRuntime({\n runtimeHook: function RuntimeHook() {\n return useChatThreadRuntime(options);\n },\n adapter: cloudAdapter,\n allowNesting: true,\n });\n};\n"],"mappings":";;;;;;;;;
|
|
1
|
+
{"version":3,"file":"useChatRuntime.js","names":[],"sources":["../../../src/ui/use-chat/useChatRuntime.ts"],"sourcesContent":["\"use client\";\n\nimport { useChat, type UIMessage } from \"@ai-sdk/react\";\nimport type { AssistantCloud } from \"assistant-cloud\";\nimport {\n pickExternalStoreSharedOptions,\n type AssistantRuntime,\n type ExternalStoreSharedOptions,\n} from \"@assistant-ui/core\";\nimport {\n useCloudThreadListAdapter,\n useRemoteThreadListRuntime,\n} from \"@assistant-ui/core/react\";\nimport { useAui, useAuiState } from \"@assistant-ui/store\";\nimport {\n useAISDKRuntime,\n type AISDKRuntimeAdapter,\n type CustomToCreateMessageFunction,\n} from \"./useAISDKRuntime\";\nimport type { ChatInit, ChatTransport } from \"ai\";\nimport { AssistantChatTransport } from \"./AssistantChatTransport\";\nimport type { AssistantChatResumableOptions } from \"../resumable\";\nimport { useEffect, useMemo, useRef } from \"react\";\n\nexport type UseChatRuntimeOptions<UI_MESSAGE extends UIMessage = UIMessage> =\n ChatInit<UI_MESSAGE> &\n ExternalStoreSharedOptions & {\n cloud?: AssistantCloud | undefined;\n adapters?: AISDKRuntimeAdapter[\"adapters\"] | undefined;\n toCreateMessage?: CustomToCreateMessageFunction;\n onResume?: AISDKRuntimeAdapter[\"onResume\"];\n joinStrategy?: AISDKRuntimeAdapter[\"joinStrategy\"];\n };\n\nconst useDynamicChatTransport = <UI_MESSAGE extends UIMessage = UIMessage>(\n transport: ChatTransport<UI_MESSAGE>,\n): ChatTransport<UI_MESSAGE> => {\n const transportRef = useRef<ChatTransport<UI_MESSAGE>>(transport);\n useEffect(() => {\n transportRef.current = transport;\n });\n const dynamicTransport = useMemo(\n () =>\n new Proxy(transportRef.current, {\n get(_, prop) {\n const res =\n transportRef.current[prop as keyof ChatTransport<UI_MESSAGE>];\n return typeof res === \"function\"\n ? res.bind(transportRef.current)\n : res;\n },\n }),\n [],\n );\n return dynamicTransport;\n};\n\nconst getResumableAdapter = <UI_MESSAGE extends UIMessage>(\n transport: ChatTransport<UI_MESSAGE>,\n): AssistantChatResumableOptions | undefined => {\n if (transport instanceof AssistantChatTransport) {\n return transport.getResumableAdapter();\n }\n const candidate = (transport as { getResumableAdapter?: () => unknown })\n .getResumableAdapter;\n if (typeof candidate !== \"function\") return undefined;\n return candidate.call(transport) as AssistantChatResumableOptions | undefined;\n};\n\nconst useChatThreadRuntime = <UI_MESSAGE extends UIMessage = UIMessage>(\n options?: UseChatRuntimeOptions<UI_MESSAGE>,\n): AssistantRuntime => {\n const {\n adapters,\n transport: transportOptions,\n toCreateMessage,\n isDisabled: _isDisabled,\n isSendDisabled: _isSendDisabled,\n unstable_capabilities: _unstable_capabilities,\n suggestions: _suggestions,\n onResume,\n joinStrategy,\n ...chatOptions\n } = options ?? {};\n // peel guard: any shared key left in `chatOptions` collapses this to `never`\n true satisfies keyof typeof chatOptions &\n keyof ExternalStoreSharedOptions extends never\n ? true\n : never;\n\n const transport = useDynamicChatTransport(\n transportOptions ?? new AssistantChatTransport(),\n );\n\n const id = useAuiState((s) => s.threadListItem.id);\n const aui = useAui();\n const chat = useChat({\n ...chatOptions,\n id,\n transport,\n });\n\n const runtime = useAISDKRuntime(chat, {\n adapters,\n ...pickExternalStoreSharedOptions(options ?? {}),\n ...(toCreateMessage && { toCreateMessage }),\n ...(onResume && { onResume }),\n ...(joinStrategy && { joinStrategy }),\n });\n\n if (transport instanceof AssistantChatTransport) {\n transport.setRuntime(runtime);\n transport.__internal_setGetThreadListItem(() =>\n aui.threadListItem.source ? aui.threadListItem() : undefined,\n );\n }\n\n const resumeFiredRef = useRef(false);\n useEffect(() => {\n if (resumeFiredRef.current) return;\n const adapter = getResumableAdapter(transport);\n if (!adapter) return;\n const pending = adapter.storage.getStreamId();\n if (!pending) return;\n resumeFiredRef.current = true;\n chat.resumeStream().catch((err: unknown) => {\n console.warn(\n \"[assistant-ui] resumable: resume failed; clearing stored stream id\",\n err,\n );\n adapter.storage.clear();\n });\n }, [transport, chat]);\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 = useCloudThreadListAdapter({ cloud });\n return useRemoteThreadListRuntime({\n runtimeHook: function RuntimeHook() {\n return useChatThreadRuntime(options);\n },\n adapter: cloudAdapter,\n allowNesting: true,\n });\n};\n"],"mappings":";;;;;;;;;AAkCA,MAAM,2BACJ,cAC8B;CAC9B,MAAM,eAAe,OAAkC,SAAS;CAChE,gBAAgB;EACd,aAAa,UAAU;CACzB,CAAC;CAcD,OAbyB,cAErB,IAAI,MAAM,aAAa,SAAS,EAC9B,IAAI,GAAG,MAAM;EACX,MAAM,MACJ,aAAa,QAAQ;EACvB,OAAO,OAAO,QAAQ,aAClB,IAAI,KAAK,aAAa,OAAO,IAC7B;CACN,EACF,CAAC,GACH,CAAC,CAEmB;AACxB;AAEA,MAAM,uBACJ,cAC8C;CAC9C,IAAI,qBAAqB,wBACvB,OAAO,UAAU,oBAAoB;CAEvC,MAAM,YAAa,UAChB;CACH,IAAI,OAAO,cAAc,YAAY,OAAO,KAAA;CAC5C,OAAO,UAAU,KAAK,SAAS;AACjC;AAEA,MAAM,wBACJ,YACqB;CACrB,MAAM,EACJ,UACA,WAAW,kBACX,iBACA,YAAY,aACZ,gBAAgB,iBAChB,uBAAuB,wBACvB,aAAa,cACb,UACA,cACA,GAAG,gBACD,WAAW,CAAC;CAOhB,MAAM,YAAY,wBAChB,oBAAoB,IAAI,uBAAuB,CACjD;CAEA,MAAM,KAAK,aAAa,MAAM,EAAE,eAAe,EAAE;CACjD,MAAM,MAAM,OAAO;CACnB,MAAM,OAAO,QAAQ;EACnB,GAAG;EACH;EACA;CACF,CAAC;CAED,MAAM,UAAU,gBAAgB,MAAM;EACpC;EACA,GAAG,+BAA+B,WAAW,CAAC,CAAC;EAC/C,GAAI,mBAAmB,EAAE,gBAAgB;EACzC,GAAI,YAAY,EAAE,SAAS;EAC3B,GAAI,gBAAgB,EAAE,aAAa;CACrC,CAAC;CAED,IAAI,qBAAqB,wBAAwB;EAC/C,UAAU,WAAW,OAAO;EAC5B,UAAU,sCACR,IAAI,eAAe,SAAS,IAAI,eAAe,IAAI,KAAA,CACrD;CACF;CAEA,MAAM,iBAAiB,OAAO,KAAK;CACnC,gBAAgB;EACd,IAAI,eAAe,SAAS;EAC5B,MAAM,UAAU,oBAAoB,SAAS;EAC7C,IAAI,CAAC,SAAS;EAEd,IAAI,CADY,QAAQ,QAAQ,YACrB,GAAG;EACd,eAAe,UAAU;EACzB,KAAK,aAAa,CAAC,CAAC,OAAO,QAAiB;GAC1C,QAAQ,KACN,sEACA,GACF;GACA,QAAQ,QAAQ,MAAM;EACxB,CAAC;CACH,GAAG,CAAC,WAAW,IAAI,CAAC;CAEpB,OAAO;AACT;AAEA,MAAa,kBAA4D,EACvE,OACA,GAAG,YACkC,CAAC,MAAwB;CAE9D,OAAO,2BAA2B;EAChC,aAAa,SAAS,cAAc;GAClC,OAAO,qBAAqB,OAAO;EACrC;EACA,SALmB,0BAA0B,EAAE,MAAM,CAKjC;EACpB,cAAc;CAChB,CAAC;AACH"}
|
|
@@ -3,7 +3,10 @@ import { AssistantRuntime, ExportedMessageRepository, MessageFormatAdapter, Mess
|
|
|
3
3
|
|
|
4
4
|
//#region src/ui/use-chat/useExternalHistory.d.ts
|
|
5
5
|
declare const toExportedMessageRepository: <TMessage>(toThreadMessages: (messages: TMessage[]) => ThreadMessage[], messages: MessageFormatRepository<TMessage>) => ExportedMessageRepository;
|
|
6
|
-
declare const useExternalHistory: <TMessage>(runtimeRef: RefObject<AssistantRuntime>, historyAdapter: ThreadHistoryAdapter | undefined, toThreadMessages: (messages: TMessage[]) => ThreadMessage[], storageFormatAdapter: MessageFormatAdapter<TMessage, any>, onSetMessages: (messages: TMessage[]) => void) =>
|
|
6
|
+
declare const useExternalHistory: <TMessage>(runtimeRef: RefObject<AssistantRuntime>, historyAdapter: ThreadHistoryAdapter | undefined, toThreadMessages: (messages: TMessage[]) => ThreadMessage[], storageFormatAdapter: MessageFormatAdapter<TMessage, any>, onSetMessages: (messages: TMessage[]) => void) => {
|
|
7
|
+
isLoading: boolean;
|
|
8
|
+
deleteMessage: (messageId: string) => Promise<void>;
|
|
9
|
+
};
|
|
7
10
|
//#endregion
|
|
8
11
|
export { toExportedMessageRepository, useExternalHistory };
|
|
9
12
|
//# sourceMappingURL=useExternalHistory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useExternalHistory.d.ts","names":[],"sources":["../../../src/ui/use-chat/useExternalHistory.ts"],"mappings":";;;;cAsBa,2BAAA,aACX,gBAAA,GAAmB,QAAA,EAAU,QAAA,OAAe,aAAA,IAC5C,QAAA,EAAU,uBAAA,CAAwB,QAAA,MACjC,yBAAA;AAAA,cAsBU,kBAAA,aACX,UAAA,EAAY,SAAA,CAAU,gBAAA,GACtB,cAAA,EAAgB,oBAAA,cAChB,gBAAA,GAAmB,QAAA,EAAU,QAAA,OAAe,aAAA,IAC5C,oBAAA,EAAsB,oBAAA,CAAqB,QAAA,QAC3C,aAAA,GAAgB,QAAA,EAAU,QAAA"}
|
|
1
|
+
{"version":3,"file":"useExternalHistory.d.ts","names":[],"sources":["../../../src/ui/use-chat/useExternalHistory.ts"],"mappings":";;;;cAsBa,2BAAA,aACX,gBAAA,GAAmB,QAAA,EAAU,QAAA,OAAe,aAAA,IAC5C,QAAA,EAAU,uBAAA,CAAwB,QAAA,MACjC,yBAAA;AAAA,cAsBU,kBAAA,aACX,UAAA,EAAY,SAAA,CAAU,gBAAA,GACtB,cAAA,EAAgB,oBAAA,cAChB,gBAAA,GAAmB,QAAA,EAAU,QAAA,OAAe,aAAA,IAC5C,oBAAA,EAAsB,oBAAA,CAAqB,QAAA,QAC3C,aAAA,GAAgB,QAAA,EAAU,QAAA;;wCAmPA,OAAA;AAAA"}
|
|
@@ -185,7 +185,31 @@ const useExternalHistory = (runtimeRef, historyAdapter, toThreadMessages, storag
|
|
|
185
185
|
storageFormatAdapter,
|
|
186
186
|
runtimeRef
|
|
187
187
|
]);
|
|
188
|
-
return
|
|
188
|
+
return {
|
|
189
|
+
isLoading,
|
|
190
|
+
deleteMessage: useCallback(async (messageId) => {
|
|
191
|
+
if (!formatAdapter?.delete) return;
|
|
192
|
+
const messages = runtimeRef.current.thread.getState().messages;
|
|
193
|
+
const messageIndex = messages.findIndex((m) => m.id === messageId);
|
|
194
|
+
if (messageIndex === -1) return;
|
|
195
|
+
const previousInnerMessages = messages.slice(0, messageIndex).flatMap(getExternalStoreMessages);
|
|
196
|
+
let parentId = previousInnerMessages.at(-1) ? storageFormatAdapter.getId(previousInnerMessages.at(-1)) : null;
|
|
197
|
+
const itemsToDelete = getExternalStoreMessages(messages[messageIndex]).map((message) => {
|
|
198
|
+
const item = {
|
|
199
|
+
parentId,
|
|
200
|
+
message
|
|
201
|
+
};
|
|
202
|
+
parentId = storageFormatAdapter.getId(message);
|
|
203
|
+
return item;
|
|
204
|
+
});
|
|
205
|
+
await formatAdapter.delete(itemsToDelete);
|
|
206
|
+
historyIds.current.delete(messageId);
|
|
207
|
+
}, [
|
|
208
|
+
formatAdapter,
|
|
209
|
+
runtimeRef,
|
|
210
|
+
storageFormatAdapter
|
|
211
|
+
])
|
|
212
|
+
};
|
|
189
213
|
};
|
|
190
214
|
//#endregion
|
|
191
215
|
export { toExportedMessageRepository, useExternalHistory };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useExternalHistory.js","names":[],"sources":["../../../src/ui/use-chat/useExternalHistory.ts"],"sourcesContent":["\"use client\";\n\nimport type {\n AssistantRuntime,\n ThreadHistoryAdapter,\n ThreadMessage,\n MessageFormatAdapter,\n MessageFormatRepository,\n ExportedMessageRepository,\n} from \"@assistant-ui/core\";\nimport { getExternalStoreMessages } from \"@assistant-ui/core\";\nimport { MessageRepository } from \"@assistant-ui/core/internal\";\nimport { useAui } from \"@assistant-ui/store\";\nimport {\n useRef,\n useEffect,\n useState,\n type RefObject,\n useCallback,\n useMemo,\n} from \"react\";\n\nexport const toExportedMessageRepository = <TMessage>(\n toThreadMessages: (messages: TMessage[]) => ThreadMessage[],\n messages: MessageFormatRepository<TMessage>,\n): ExportedMessageRepository => {\n const survivingIds = new Set<string>();\n const survivors = messages.messages.flatMap((m) => {\n const message = toThreadMessages([m.message])[0];\n if (!message) {\n console.warn(\"Skipping a stored message that could not be loaded.\");\n return [];\n }\n if (m.parentId && !survivingIds.has(m.parentId)) return [];\n survivingIds.add(message.id);\n return [{ ...m, message }];\n });\n\n return {\n headId:\n messages.headId && survivingIds.has(messages.headId)\n ? messages.headId\n : null,\n messages: survivors,\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\n const aui = useAui();\n const optionalThreadListItem = useCallback(\n () => (aui.threadListItem.source ? aui.threadListItem() : null),\n [aui],\n );\n\n const [isLoading, setIsLoading] = useState(false);\n\n const historyIds = useRef(new Set<string>());\n\n const onSetMessagesRef = useRef(onSetMessages);\n useEffect(() => {\n onSetMessagesRef.current = onSetMessages;\n });\n\n const formatAdapter = useMemo(() => {\n if (!historyAdapter) return undefined;\n if (!historyAdapter.withFormat) {\n throw new Error(\n \"useAISDKRuntime: ThreadHistoryAdapter is missing the required `withFormat` method.\",\n );\n }\n return historyAdapter.withFormat<TMessage, any>(storageFormatAdapter);\n }, [historyAdapter, storageFormatAdapter]);\n\n useEffect(() => {\n if (!formatAdapter || loadedRef.current) return;\n\n const loadHistory = async () => {\n setIsLoading(true);\n try {\n const repo = await formatAdapter.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.flatMap(getExternalStoreMessages<TMessage>),\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 loadedRef.current = true;\n\n if (!optionalThreadListItem()?.getState().remoteId) {\n setIsLoading(false);\n return;\n }\n\n loadHistory();\n }, [formatAdapter, toThreadMessages, runtimeRef, optionalThreadListItem]);\n\n const runStartRef = useRef<number | null>(null);\n const persistTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const stepBoundariesRef = useRef<number[]>([]);\n const wasRunningRef = useRef(false);\n const toolCallCountRef = useRef(0);\n\n useEffect(() => {\n if (!formatAdapter) return;\n\n const unsubscribe = runtimeRef.current.thread.subscribe(() => {\n const { isRunning } = runtimeRef.current.thread.getState();\n const wasRunning = wasRunningRef.current;\n wasRunningRef.current = isRunning;\n\n // Track step boundaries by content changes (more reliable than isRunning)\n if (runStartRef.current != null) {\n const lastMsg = runtimeRef.current.thread.getState().messages.at(-1);\n if (lastMsg?.role === \"assistant\") {\n const currentToolCallCount = lastMsg.content.filter(\n (p) => p.type === \"tool-call\",\n ).length;\n while (toolCallCountRef.current < currentToolCallCount) {\n stepBoundariesRef.current.push(Date.now() - runStartRef.current);\n toolCallCountRef.current++;\n }\n }\n }\n\n if (isRunning) {\n if (runStartRef.current == null) {\n runStartRef.current = Date.now();\n stepBoundariesRef.current = [];\n toolCallCountRef.current = 0;\n }\n // Cancel any pending persist — isRunning went back to true\n if (persistTimerRef.current) {\n clearTimeout(persistTimerRef.current);\n persistTimerRef.current = null;\n }\n return;\n }\n\n // Only act on the true→false transition\n if (!wasRunning) return;\n\n // Record step boundary offset (synchronous for accuracy)\n if (runStartRef.current != null) {\n stepBoundariesRef.current.push(Date.now() - runStartRef.current);\n }\n\n // Debounce: wait one macrotask so agentic step flickers are absorbed\n if (persistTimerRef.current) clearTimeout(persistTimerRef.current);\n persistTimerRef.current = setTimeout(async () => {\n persistTimerRef.current = null;\n\n // Re-read latest state — may have changed since the timeout was scheduled\n const latest = runtimeRef.current.thread.getState();\n if (latest.isRunning) return; // was just a flicker\n\n // Derive durationMs from the last boundary (covers all steps)\n const boundaries = stepBoundariesRef.current;\n const durationMs =\n boundaries.length > 0 ? boundaries.at(-1) : undefined;\n\n // Fallback: if only 1 boundary but message has multiple steps, distribute evenly\n if (boundaries.length === 1 && durationMs != null) {\n const lastAssistant = latest.messages.findLast(\n (m) => m.role === \"assistant\",\n );\n if (lastAssistant) {\n const tcCount = lastAssistant.content.filter(\n (p) => p.type === \"tool-call\",\n ).length;\n if (tcCount > 0) {\n const totalSteps = tcCount + 1;\n const stepDur = durationMs / totalSteps;\n boundaries.length = 0;\n for (let i = 0; i < totalSteps; i++) {\n boundaries.push(Math.round((i + 1) * stepDur));\n }\n }\n }\n }\n\n // Build per-step timestamps when there are multiple steps\n const stepTimestamps =\n boundaries.length > 1\n ? boundaries.map((endMs, i) => ({\n start_ms: i === 0 ? 0 : boundaries[i - 1]!,\n end_ms: endMs,\n }))\n : undefined;\n\n runStartRef.current = null;\n stepBoundariesRef.current = [];\n\n const telemetryOptions = {\n ...(durationMs != null ? { durationMs } : undefined),\n ...(stepTimestamps != null ? { stepTimestamps } : undefined),\n };\n\n const { messages } = latest;\n let lastInnerMessageId: string | null = null;\n\n const getLastInnerId = (msgs: TMessage[]): string | null =>\n msgs.length > 0 ? storageFormatAdapter.getId(msgs.at(-1)!) : null;\n\n const toBatchItems = (msgs: TMessage[]) =>\n msgs.map((msg, idx) => ({\n parentId:\n idx === 0\n ? lastInnerMessageId\n : storageFormatAdapter.getId(msgs[idx - 1]!),\n message: msg,\n }));\n\n for (const message of messages) {\n const innerMessages = getExternalStoreMessages<TMessage>(message);\n\n const isReady =\n message.status === undefined ||\n message.status.type === \"complete\" ||\n message.status.type === \"incomplete\";\n\n if (!isReady) {\n lastInnerMessageId =\n getLastInnerId(innerMessages) ?? lastInnerMessageId;\n continue;\n }\n\n if (historyIds.current.has(message.id)) {\n if (durationMs !== undefined) {\n let parentId = lastInnerMessageId;\n for (const innerMessage of innerMessages) {\n try {\n await formatAdapter.update?.(\n { parentId, message: innerMessage },\n storageFormatAdapter.getId(innerMessage),\n );\n } catch {\n // ignore update failures to avoid breaking the message processing loop\n }\n parentId = storageFormatAdapter.getId(innerMessage);\n }\n }\n lastInnerMessageId =\n getLastInnerId(innerMessages) ?? lastInnerMessageId;\n continue;\n }\n historyIds.current.add(message.id);\n\n const batchItems = toBatchItems(innerMessages);\n for (const item of batchItems) {\n await formatAdapter.append(item);\n }\n\n lastInnerMessageId =\n getLastInnerId(innerMessages) ?? lastInnerMessageId;\n\n formatAdapter.reportTelemetry?.(batchItems, telemetryOptions);\n }\n }, 0);\n });\n\n return () => {\n unsubscribe();\n if (persistTimerRef.current) {\n clearTimeout(persistTimerRef.current);\n persistTimerRef.current = null;\n }\n };\n }, [formatAdapter, storageFormatAdapter, runtimeRef]);\n\n return isLoading;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useExternalHistory.js","names":[],"sources":["../../../src/ui/use-chat/useExternalHistory.ts"],"sourcesContent":["\"use client\";\n\nimport type {\n AssistantRuntime,\n ThreadHistoryAdapter,\n ThreadMessage,\n MessageFormatAdapter,\n MessageFormatRepository,\n ExportedMessageRepository,\n} from \"@assistant-ui/core\";\nimport { getExternalStoreMessages } from \"@assistant-ui/core\";\nimport { MessageRepository } from \"@assistant-ui/core/internal\";\nimport { useAui } from \"@assistant-ui/store\";\nimport {\n useRef,\n useEffect,\n useState,\n type RefObject,\n useCallback,\n useMemo,\n} from \"react\";\n\nexport const toExportedMessageRepository = <TMessage>(\n toThreadMessages: (messages: TMessage[]) => ThreadMessage[],\n messages: MessageFormatRepository<TMessage>,\n): ExportedMessageRepository => {\n const survivingIds = new Set<string>();\n const survivors = messages.messages.flatMap((m) => {\n const message = toThreadMessages([m.message])[0];\n if (!message) {\n console.warn(\"Skipping a stored message that could not be loaded.\");\n return [];\n }\n if (m.parentId && !survivingIds.has(m.parentId)) return [];\n survivingIds.add(message.id);\n return [{ ...m, message }];\n });\n\n return {\n headId:\n messages.headId && survivingIds.has(messages.headId)\n ? messages.headId\n : null,\n messages: survivors,\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\n const aui = useAui();\n const optionalThreadListItem = useCallback(\n () => (aui.threadListItem.source ? aui.threadListItem() : null),\n [aui],\n );\n\n const [isLoading, setIsLoading] = useState(false);\n\n const historyIds = useRef(new Set<string>());\n\n const onSetMessagesRef = useRef(onSetMessages);\n useEffect(() => {\n onSetMessagesRef.current = onSetMessages;\n });\n\n const formatAdapter = useMemo(() => {\n if (!historyAdapter) return undefined;\n if (!historyAdapter.withFormat) {\n throw new Error(\n \"useAISDKRuntime: ThreadHistoryAdapter is missing the required `withFormat` method.\",\n );\n }\n return historyAdapter.withFormat<TMessage, any>(storageFormatAdapter);\n }, [historyAdapter, storageFormatAdapter]);\n\n useEffect(() => {\n if (!formatAdapter || loadedRef.current) return;\n\n const loadHistory = async () => {\n setIsLoading(true);\n try {\n const repo = await formatAdapter.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.flatMap(getExternalStoreMessages<TMessage>),\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 loadedRef.current = true;\n\n if (!optionalThreadListItem()?.getState().remoteId) {\n setIsLoading(false);\n return;\n }\n\n loadHistory();\n }, [formatAdapter, toThreadMessages, runtimeRef, optionalThreadListItem]);\n\n const runStartRef = useRef<number | null>(null);\n const persistTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const stepBoundariesRef = useRef<number[]>([]);\n const wasRunningRef = useRef(false);\n const toolCallCountRef = useRef(0);\n\n useEffect(() => {\n if (!formatAdapter) return;\n\n const unsubscribe = runtimeRef.current.thread.subscribe(() => {\n const { isRunning } = runtimeRef.current.thread.getState();\n const wasRunning = wasRunningRef.current;\n wasRunningRef.current = isRunning;\n\n // Track step boundaries by content changes (more reliable than isRunning)\n if (runStartRef.current != null) {\n const lastMsg = runtimeRef.current.thread.getState().messages.at(-1);\n if (lastMsg?.role === \"assistant\") {\n const currentToolCallCount = lastMsg.content.filter(\n (p) => p.type === \"tool-call\",\n ).length;\n while (toolCallCountRef.current < currentToolCallCount) {\n stepBoundariesRef.current.push(Date.now() - runStartRef.current);\n toolCallCountRef.current++;\n }\n }\n }\n\n if (isRunning) {\n if (runStartRef.current == null) {\n runStartRef.current = Date.now();\n stepBoundariesRef.current = [];\n toolCallCountRef.current = 0;\n }\n // Cancel any pending persist — isRunning went back to true\n if (persistTimerRef.current) {\n clearTimeout(persistTimerRef.current);\n persistTimerRef.current = null;\n }\n return;\n }\n\n // Only act on the true→false transition\n if (!wasRunning) return;\n\n // Record step boundary offset (synchronous for accuracy)\n if (runStartRef.current != null) {\n stepBoundariesRef.current.push(Date.now() - runStartRef.current);\n }\n\n // Debounce: wait one macrotask so agentic step flickers are absorbed\n if (persistTimerRef.current) clearTimeout(persistTimerRef.current);\n persistTimerRef.current = setTimeout(async () => {\n persistTimerRef.current = null;\n\n // Re-read latest state — may have changed since the timeout was scheduled\n const latest = runtimeRef.current.thread.getState();\n if (latest.isRunning) return; // was just a flicker\n\n // Derive durationMs from the last boundary (covers all steps)\n const boundaries = stepBoundariesRef.current;\n const durationMs =\n boundaries.length > 0 ? boundaries.at(-1) : undefined;\n\n // Fallback: if only 1 boundary but message has multiple steps, distribute evenly\n if (boundaries.length === 1 && durationMs != null) {\n const lastAssistant = latest.messages.findLast(\n (m) => m.role === \"assistant\",\n );\n if (lastAssistant) {\n const tcCount = lastAssistant.content.filter(\n (p) => p.type === \"tool-call\",\n ).length;\n if (tcCount > 0) {\n const totalSteps = tcCount + 1;\n const stepDur = durationMs / totalSteps;\n boundaries.length = 0;\n for (let i = 0; i < totalSteps; i++) {\n boundaries.push(Math.round((i + 1) * stepDur));\n }\n }\n }\n }\n\n // Build per-step timestamps when there are multiple steps\n const stepTimestamps =\n boundaries.length > 1\n ? boundaries.map((endMs, i) => ({\n start_ms: i === 0 ? 0 : boundaries[i - 1]!,\n end_ms: endMs,\n }))\n : undefined;\n\n runStartRef.current = null;\n stepBoundariesRef.current = [];\n\n const telemetryOptions = {\n ...(durationMs != null ? { durationMs } : undefined),\n ...(stepTimestamps != null ? { stepTimestamps } : undefined),\n };\n\n const { messages } = latest;\n let lastInnerMessageId: string | null = null;\n\n const getLastInnerId = (msgs: TMessage[]): string | null =>\n msgs.length > 0 ? storageFormatAdapter.getId(msgs.at(-1)!) : null;\n\n const toBatchItems = (msgs: TMessage[]) =>\n msgs.map((msg, idx) => ({\n parentId:\n idx === 0\n ? lastInnerMessageId\n : storageFormatAdapter.getId(msgs[idx - 1]!),\n message: msg,\n }));\n\n for (const message of messages) {\n const innerMessages = getExternalStoreMessages<TMessage>(message);\n\n const isReady =\n message.status === undefined ||\n message.status.type === \"complete\" ||\n message.status.type === \"incomplete\";\n\n if (!isReady) {\n lastInnerMessageId =\n getLastInnerId(innerMessages) ?? lastInnerMessageId;\n continue;\n }\n\n if (historyIds.current.has(message.id)) {\n if (durationMs !== undefined) {\n let parentId = lastInnerMessageId;\n for (const innerMessage of innerMessages) {\n try {\n await formatAdapter.update?.(\n { parentId, message: innerMessage },\n storageFormatAdapter.getId(innerMessage),\n );\n } catch {\n // ignore update failures to avoid breaking the message processing loop\n }\n parentId = storageFormatAdapter.getId(innerMessage);\n }\n }\n lastInnerMessageId =\n getLastInnerId(innerMessages) ?? lastInnerMessageId;\n continue;\n }\n historyIds.current.add(message.id);\n\n const batchItems = toBatchItems(innerMessages);\n for (const item of batchItems) {\n await formatAdapter.append(item);\n }\n\n lastInnerMessageId =\n getLastInnerId(innerMessages) ?? lastInnerMessageId;\n\n formatAdapter.reportTelemetry?.(batchItems, telemetryOptions);\n }\n }, 0);\n });\n\n return () => {\n unsubscribe();\n if (persistTimerRef.current) {\n clearTimeout(persistTimerRef.current);\n persistTimerRef.current = null;\n }\n };\n }, [formatAdapter, storageFormatAdapter, runtimeRef]);\n\n const deleteMessage = useCallback(\n async (messageId: string) => {\n if (!formatAdapter?.delete) return;\n\n const messages = runtimeRef.current.thread.getState().messages;\n const messageIndex = messages.findIndex((m) => m.id === messageId);\n if (messageIndex === -1) return;\n\n const previousInnerMessages = messages\n .slice(0, messageIndex)\n .flatMap(getExternalStoreMessages<TMessage>);\n let parentId = previousInnerMessages.at(-1)\n ? storageFormatAdapter.getId(previousInnerMessages.at(-1)!)\n : null;\n const itemsToDelete = getExternalStoreMessages<TMessage>(\n messages[messageIndex]!,\n ).map((message) => {\n const item = { parentId, message };\n parentId = storageFormatAdapter.getId(message);\n return item;\n });\n\n await formatAdapter.delete(itemsToDelete);\n\n historyIds.current.delete(messageId);\n },\n [formatAdapter, runtimeRef, storageFormatAdapter],\n );\n\n return { isLoading, deleteMessage };\n};\n"],"mappings":";;;;;;AAsBA,MAAa,+BACX,kBACA,aAC8B;CAC9B,MAAM,+BAAe,IAAI,IAAY;CACrC,MAAM,YAAY,SAAS,SAAS,SAAS,MAAM;EACjD,MAAM,UAAU,iBAAiB,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;EAC9C,IAAI,CAAC,SAAS;GACZ,QAAQ,KAAK,qDAAqD;GAClE,OAAO,CAAC;EACV;EACA,IAAI,EAAE,YAAY,CAAC,aAAa,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;EACzD,aAAa,IAAI,QAAQ,EAAE;EAC3B,OAAO,CAAC;GAAE,GAAG;GAAG;EAAQ,CAAC;CAC3B,CAAC;CAED,OAAO;EACL,QACE,SAAS,UAAU,aAAa,IAAI,SAAS,MAAM,IAC/C,SAAS,SACT;EACN,UAAU;CACZ;AACF;AAEA,MAAa,sBACX,YACA,gBACA,kBACA,sBACA,kBACG;CACH,MAAM,YAAY,OAAO,KAAK;CAE9B,MAAM,MAAM,OAAO;CACnB,MAAM,yBAAyB,kBACtB,IAAI,eAAe,SAAS,IAAI,eAAe,IAAI,MAC1D,CAAC,GAAG,CACN;CAEA,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAEhD,MAAM,aAAa,uBAAO,IAAI,IAAY,CAAC;CAE3C,MAAM,mBAAmB,OAAO,aAAa;CAC7C,gBAAgB;EACd,iBAAiB,UAAU;CAC7B,CAAC;CAED,MAAM,gBAAgB,cAAc;EAClC,IAAI,CAAC,gBAAgB,OAAO,KAAA;EAC5B,IAAI,CAAC,eAAe,YAClB,MAAM,IAAI,MACR,oFACF;EAEF,OAAO,eAAe,WAA0B,oBAAoB;CACtE,GAAG,CAAC,gBAAgB,oBAAoB,CAAC;CAEzC,gBAAgB;EACd,IAAI,CAAC,iBAAiB,UAAU,SAAS;EAEzC,MAAM,cAAc,YAAY;GAC9B,aAAa,IAAI;GACjB,IAAI;IACF,MAAM,OAAO,MAAM,cAAc,KAAK;IACtC,IAAI,QAAQ,KAAK,SAAS,SAAS,GAAG;KACpC,MAAM,YAAY,4BAA4B,kBAAkB,IAAI;KACpE,WAAW,QAAQ,OAAO,OAAO,SAAS;KAE1C,MAAM,WAAW,IAAI,kBAAkB;KACvC,SAAS,OAAO,SAAS;KACzB,MAAM,WAAW,SAAS,YAAY;KAEtC,iBAAiB,QACf,SAAS,QAAQ,wBAAkC,CACrD;KAEA,WAAW,UAAU,IAAI,IACvB,UAAU,SAAS,KAAK,MAAM,EAAE,QAAQ,EAAE,CAC5C;IACF;GACF,SAAS,OAAO;IACd,QAAQ,MAAM,mCAAmC,KAAK;GACxD,UAAU;IACR,aAAa,KAAK;GACpB;EACF;EAEA,UAAU,UAAU;EAEpB,IAAI,CAAC,uBAAuB,CAAC,EAAE,SAAS,CAAC,CAAC,UAAU;GAClD,aAAa,KAAK;GAClB;EACF;EAEA,YAAY;CACd,GAAG;EAAC;EAAe;EAAkB;EAAY;CAAsB,CAAC;CAExE,MAAM,cAAc,OAAsB,IAAI;CAC9C,MAAM,kBAAkB,OAA6C,IAAI;CACzE,MAAM,oBAAoB,OAAiB,CAAC,CAAC;CAC7C,MAAM,gBAAgB,OAAO,KAAK;CAClC,MAAM,mBAAmB,OAAO,CAAC;CAEjC,gBAAgB;EACd,IAAI,CAAC,eAAe;EAEpB,MAAM,cAAc,WAAW,QAAQ,OAAO,gBAAgB;GAC5D,MAAM,EAAE,cAAc,WAAW,QAAQ,OAAO,SAAS;GACzD,MAAM,aAAa,cAAc;GACjC,cAAc,UAAU;GAGxB,IAAI,YAAY,WAAW,MAAM;IAC/B,MAAM,UAAU,WAAW,QAAQ,OAAO,SAAS,CAAC,CAAC,SAAS,GAAG,EAAE;IACnE,IAAI,SAAS,SAAS,aAAa;KACjC,MAAM,uBAAuB,QAAQ,QAAQ,QAC1C,MAAM,EAAE,SAAS,WACpB,CAAC,CAAC;KACF,OAAO,iBAAiB,UAAU,sBAAsB;MACtD,kBAAkB,QAAQ,KAAK,KAAK,IAAI,IAAI,YAAY,OAAO;MAC/D,iBAAiB;KACnB;IACF;GACF;GAEA,IAAI,WAAW;IACb,IAAI,YAAY,WAAW,MAAM;KAC/B,YAAY,UAAU,KAAK,IAAI;KAC/B,kBAAkB,UAAU,CAAC;KAC7B,iBAAiB,UAAU;IAC7B;IAEA,IAAI,gBAAgB,SAAS;KAC3B,aAAa,gBAAgB,OAAO;KACpC,gBAAgB,UAAU;IAC5B;IACA;GACF;GAGA,IAAI,CAAC,YAAY;GAGjB,IAAI,YAAY,WAAW,MACzB,kBAAkB,QAAQ,KAAK,KAAK,IAAI,IAAI,YAAY,OAAO;GAIjE,IAAI,gBAAgB,SAAS,aAAa,gBAAgB,OAAO;GACjE,gBAAgB,UAAU,WAAW,YAAY;IAC/C,gBAAgB,UAAU;IAG1B,MAAM,SAAS,WAAW,QAAQ,OAAO,SAAS;IAClD,IAAI,OAAO,WAAW;IAGtB,MAAM,aAAa,kBAAkB;IACrC,MAAM,aACJ,WAAW,SAAS,IAAI,WAAW,GAAG,EAAE,IAAI,KAAA;IAG9C,IAAI,WAAW,WAAW,KAAK,cAAc,MAAM;KACjD,MAAM,gBAAgB,OAAO,SAAS,UACnC,MAAM,EAAE,SAAS,WACpB;KACA,IAAI,eAAe;MACjB,MAAM,UAAU,cAAc,QAAQ,QACnC,MAAM,EAAE,SAAS,WACpB,CAAC,CAAC;MACF,IAAI,UAAU,GAAG;OACf,MAAM,aAAa,UAAU;OAC7B,MAAM,UAAU,aAAa;OAC7B,WAAW,SAAS;OACpB,KAAK,IAAI,IAAI,GAAG,IAAI,YAAY,KAC9B,WAAW,KAAK,KAAK,OAAO,IAAI,KAAK,OAAO,CAAC;MAEjD;KACF;IACF;IAGA,MAAM,iBACJ,WAAW,SAAS,IAChB,WAAW,KAAK,OAAO,OAAO;KAC5B,UAAU,MAAM,IAAI,IAAI,WAAW,IAAI;KACvC,QAAQ;IACV,EAAE,IACF,KAAA;IAEN,YAAY,UAAU;IACtB,kBAAkB,UAAU,CAAC;IAE7B,MAAM,mBAAmB;KACvB,GAAI,cAAc,OAAO,EAAE,WAAW,IAAI,KAAA;KAC1C,GAAI,kBAAkB,OAAO,EAAE,eAAe,IAAI,KAAA;IACpD;IAEA,MAAM,EAAE,aAAa;IACrB,IAAI,qBAAoC;IAExC,MAAM,kBAAkB,SACtB,KAAK,SAAS,IAAI,qBAAqB,MAAM,KAAK,GAAG,EAAE,CAAE,IAAI;IAE/D,MAAM,gBAAgB,SACpB,KAAK,KAAK,KAAK,SAAS;KACtB,UACE,QAAQ,IACJ,qBACA,qBAAqB,MAAM,KAAK,MAAM,EAAG;KAC/C,SAAS;IACX,EAAE;IAEJ,KAAK,MAAM,WAAW,UAAU;KAC9B,MAAM,gBAAgB,yBAAmC,OAAO;KAOhE,IAAI,EAJF,QAAQ,WAAW,KAAA,KACnB,QAAQ,OAAO,SAAS,cACxB,QAAQ,OAAO,SAAS,eAEZ;MACZ,qBACE,eAAe,aAAa,KAAK;MACnC;KACF;KAEA,IAAI,WAAW,QAAQ,IAAI,QAAQ,EAAE,GAAG;MACtC,IAAI,eAAe,KAAA,GAAW;OAC5B,IAAI,WAAW;OACf,KAAK,MAAM,gBAAgB,eAAe;QACxC,IAAI;SACF,MAAM,cAAc,SAClB;UAAE;UAAU,SAAS;SAAa,GAClC,qBAAqB,MAAM,YAAY,CACzC;QACF,QAAQ,CAER;QACA,WAAW,qBAAqB,MAAM,YAAY;OACpD;MACF;MACA,qBACE,eAAe,aAAa,KAAK;MACnC;KACF;KACA,WAAW,QAAQ,IAAI,QAAQ,EAAE;KAEjC,MAAM,aAAa,aAAa,aAAa;KAC7C,KAAK,MAAM,QAAQ,YACjB,MAAM,cAAc,OAAO,IAAI;KAGjC,qBACE,eAAe,aAAa,KAAK;KAEnC,cAAc,kBAAkB,YAAY,gBAAgB;IAC9D;GACF,GAAG,CAAC;EACN,CAAC;EAED,aAAa;GACX,YAAY;GACZ,IAAI,gBAAgB,SAAS;IAC3B,aAAa,gBAAgB,OAAO;IACpC,gBAAgB,UAAU;GAC5B;EACF;CACF,GAAG;EAAC;EAAe;EAAsB;CAAU,CAAC;CA+BpD,OAAO;EAAE;EAAW,eA7BE,YACpB,OAAO,cAAsB;GAC3B,IAAI,CAAC,eAAe,QAAQ;GAE5B,MAAM,WAAW,WAAW,QAAQ,OAAO,SAAS,CAAC,CAAC;GACtD,MAAM,eAAe,SAAS,WAAW,MAAM,EAAE,OAAO,SAAS;GACjE,IAAI,iBAAiB,IAAI;GAEzB,MAAM,wBAAwB,SAC3B,MAAM,GAAG,YAAY,CAAC,CACtB,QAAQ,wBAAkC;GAC7C,IAAI,WAAW,sBAAsB,GAAG,EAAE,IACtC,qBAAqB,MAAM,sBAAsB,GAAG,EAAE,CAAE,IACxD;GACJ,MAAM,gBAAgB,yBACpB,SAAS,aACX,CAAC,CAAC,KAAK,YAAY;IACjB,MAAM,OAAO;KAAE;KAAU;IAAQ;IACjC,WAAW,qBAAqB,MAAM,OAAO;IAC7C,OAAO;GACT,CAAC;GAED,MAAM,cAAc,OAAO,aAAa;GAExC,WAAW,QAAQ,OAAO,SAAS;EACrC,GACA;GAAC;GAAe;GAAY;EAAoB,CAGlB;CAAE;AACpC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ReadonlyJSONObject } from "../../assistant-stream/dist/utils/json/json-value.js";
|
|
2
1
|
import { UIMessage } from "ai";
|
|
3
2
|
import { useExternalMessageConverter } from "@assistant-ui/core/react";
|
|
4
3
|
import { McpAppMetadata } from "@assistant-ui/core";
|
|
4
|
+
import { ReadonlyJSONObject } from "assistant-stream/utils";
|
|
5
5
|
|
|
6
6
|
//#region src/ui/utils/convertMessage.d.ts
|
|
7
7
|
type AISDKMessageConverterMetadata = useExternalMessageConverter.Metadata & {
|
|
@@ -19,7 +19,7 @@ declare const AISDKMessageConverter: {
|
|
|
19
19
|
}: {
|
|
20
20
|
messages: UIMessage<unknown, import("ai").UIDataTypes, import("ai").UITools>[];
|
|
21
21
|
isRunning: boolean;
|
|
22
|
-
joinStrategy?: "
|
|
22
|
+
joinStrategy?: import("@assistant-ui/core/react").JoinStrategy | undefined;
|
|
23
23
|
metadata?: useExternalMessageConverter.Metadata;
|
|
24
24
|
}) => import("@assistant-ui/core").ThreadMessage[];
|
|
25
25
|
toThreadMessages: (messages: UIMessage<unknown, import("ai").UIDataTypes, import("ai").UITools>[], isRunning?: boolean, metadata?: useExternalMessageConverter.Metadata) => import("@assistant-ui/core").ThreadMessage[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convertMessage.d.ts","names":[],"sources":["../../../src/ui/utils/convertMessage.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"convertMessage.d.ts","names":[],"sources":["../../../src/ui/utils/convertMessage.ts"],"mappings":";;;;;;KAwBY,6BAAA,GACV,2BAAA,CAA4B,QAAA;EAC1B,qBAAA,GAAwB,GAAA,SAAY,GAAA;EACpC,kBAAA,GAAqB,GAAA,SAAY,kBAAA;EACjC,mBAAA,GAAsB,GAAA,SAAY,cAAA;EAElC,mBAAA;AAAA;AAAA,cA8US,qBAAA;;;;;;;;;;;;;mJAlVa,aAAA;kJAEf,aAAA"}
|
|
@@ -2,6 +2,7 @@ import { unwrapModelContentEnvelope } from "../../modelContentEnvelope.js";
|
|
|
2
2
|
import { getToolName, isToolUIPart } from "ai";
|
|
3
3
|
import { createMessageConverter } from "@assistant-ui/core/react";
|
|
4
4
|
import { isMcpAppUri } from "@assistant-ui/core";
|
|
5
|
+
import { parsePartialJsonObject } from "assistant-stream/utils";
|
|
5
6
|
//#region src/ui/utils/convertMessage.ts
|
|
6
7
|
function stripClosingDelimiters(json) {
|
|
7
8
|
return json.replace(/[}\]"]+$/, "");
|
|
@@ -110,8 +111,10 @@ function convertParts(message, metadata) {
|
|
|
110
111
|
result = { error: part.approval?.reason || "Tool approval denied" };
|
|
111
112
|
}
|
|
112
113
|
let argsText = stableStringifyToolArgs(metadata.toolArgsKeyOrderCache, argsKeyOrderCacheKey, args);
|
|
113
|
-
if (part.state === "input-streaming")
|
|
114
|
-
|
|
114
|
+
if (part.state === "input-streaming") {
|
|
115
|
+
argsText = stripClosingDelimiters(argsText);
|
|
116
|
+
args = parsePartialJsonObject(argsText) ?? args;
|
|
117
|
+
} else {
|
|
115
118
|
metadata.toolArgsKeyOrderCache?.delete(argsKeyOrderCacheKey);
|
|
116
119
|
if (part.state === "output-available" || part.state === "output-error" || part.state === "output-denied") metadata.toolLastInputCache?.delete(argsKeyOrderCacheKey);
|
|
117
120
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"convertMessage.js","names":["unstable_createMessageConverter"],"sources":["../../../src/ui/utils/convertMessage.ts"],"sourcesContent":["import { isToolUIPart, getToolName, type UIMessage } from \"ai\";\nimport {\n createMessageConverter as unstable_createMessageConverter,\n type useExternalMessageConverter,\n} from \"@assistant-ui/core/react\";\nimport {\n isMcpAppUri,\n type ReasoningMessagePart,\n type ToolCallMessagePart,\n type TextMessagePart,\n type DataMessagePart,\n type SourceMessagePart,\n type SourceProviderMetadata,\n type FileMessagePart,\n type ThreadMessageLike,\n type McpAppMetadata,\n} from \"@assistant-ui/core\";\nimport type { ReadonlyJSONObject } from \"assistant-stream/utils\";\nimport { unwrapModelContentEnvelope } from \"../../modelContentEnvelope\";\n\ntype MessageMetadata = ThreadMessageLike[\"metadata\"];\nexport type AISDKMessageConverterMetadata =\n useExternalMessageConverter.Metadata & {\n toolArgsKeyOrderCache?: Map<string, Map<string, string[]>>;\n toolLastInputCache?: Map<string, ReadonlyJSONObject>;\n mcpAppMetadataCache?: Map<string, McpAppMetadata>;\n /** Id of the currently-streaming message, flagged optimistic (#4037). */\n optimisticMessageId?: string | undefined;\n };\n\nfunction stripClosingDelimiters(json: string): string {\n return json.replace(/[}\\]\"]+$/, \"\");\n}\n\nconst MCP_APP_METADATA_CACHE_MAX = 100;\n\nfunction extractMcpAppMetadata(\n part: unknown,\n cache: Map<string, McpAppMetadata> | undefined,\n): McpAppMetadata | undefined {\n if (!part || typeof part !== \"object\") return undefined;\n const meta = (part as { callProviderMetadata?: unknown })\n .callProviderMetadata;\n const mcp =\n meta && typeof meta === \"object\"\n ? (meta as { mcp?: unknown }).mcp\n : undefined;\n const app =\n mcp && typeof mcp === \"object\" ? (mcp as { app?: unknown }).app : undefined;\n let a: Record<string, unknown>;\n if (app && typeof app === \"object\") {\n a = app as Record<string, unknown>;\n } else {\n // MCP-UI tools (e.g. xmcp) surface the UI pointer as\n // result._meta[\"ui/resourceUri\"] rather than in callProviderMetadata.\n const output = (part as { output?: unknown }).output;\n const outMeta =\n output && typeof output === \"object\"\n ? (output as { _meta?: unknown })._meta\n : undefined;\n const uiResourceUri =\n outMeta && typeof outMeta === \"object\"\n ? (outMeta as Record<string, unknown>)[\"ui/resourceUri\"]\n : undefined;\n if (typeof uiResourceUri !== \"string\") return undefined;\n a = { resourceUri: uiResourceUri };\n }\n if (typeof a[\"resourceUri\"] !== \"string\") return undefined;\n if (!isMcpAppUri(a[\"resourceUri\"])) return undefined;\n const cached = cache?.get(a[\"resourceUri\"]);\n if (cached) {\n cache!.delete(a[\"resourceUri\"]);\n cache!.set(a[\"resourceUri\"], cached);\n return cached;\n }\n const out: { -readonly [K in keyof McpAppMetadata]: McpAppMetadata[K] } = {\n resourceUri: a[\"resourceUri\"],\n };\n if (typeof a[\"mimeType\"] === \"string\") out.mimeType = a[\"mimeType\"];\n if (Array.isArray(a[\"visibility\"])) {\n out.visibility = a[\"visibility\"].filter(\n (v): v is \"model\" | \"app\" => v === \"model\" || v === \"app\",\n );\n }\n if (cache) {\n if (cache.size >= MCP_APP_METADATA_CACHE_MAX) {\n const oldest = cache.keys().next().value;\n if (oldest !== undefined) cache.delete(oldest);\n }\n cache.set(a[\"resourceUri\"], out);\n }\n return out;\n}\n\nconst hasOwn = (value: object, key: string) => Object.hasOwn(value, key);\n\nconst stabilizeToolArgsValue = (\n value: unknown,\n path: string,\n keyOrderByPath: Map<string, string[]>,\n): unknown => {\n if (Array.isArray(value)) {\n return value.map((item, idx) =>\n stabilizeToolArgsValue(item, `${path}[${idx}]`, keyOrderByPath),\n );\n }\n\n if (value && typeof value === \"object\") {\n const record = value as Record<string, unknown>;\n const currentKeys = Object.keys(record);\n const previousOrder = keyOrderByPath.get(path) ?? [];\n const previousOrderSet = new Set(previousOrder);\n const nextOrder = [\n ...previousOrder.filter((key) => hasOwn(record, key)),\n ...currentKeys.filter((key) => !previousOrderSet.has(key)),\n ];\n keyOrderByPath.set(path, nextOrder);\n\n return Object.fromEntries(\n nextOrder.map((key) => [\n key,\n stabilizeToolArgsValue(record[key], `${path}.${key}`, keyOrderByPath),\n ]),\n );\n }\n\n return value;\n};\n\nfunction stableStringifyToolArgs(\n keyOrderCache: Map<string, Map<string, string[]>> | undefined,\n cacheKey: string,\n args: ReadonlyJSONObject,\n): string {\n const keyOrderByPath = keyOrderCache?.get(cacheKey) ?? new Map();\n keyOrderCache?.set(cacheKey, keyOrderByPath);\n\n const stableArgs = stabilizeToolArgsValue(\n args,\n \"$\",\n keyOrderByPath,\n ) as ReadonlyJSONObject;\n return JSON.stringify(stableArgs);\n}\n\nfunction getToolApprovalAndInterrupt(\n part: {\n approval?:\n | {\n id: string;\n approved?: boolean;\n reason?: string;\n isAutomatic?: boolean;\n }\n | undefined;\n },\n toolStatus: { type: string; payload?: unknown } | undefined,\n): {\n approval?: NonNullable<ToolCallMessagePart[\"approval\"]>;\n interrupt?: NonNullable<ToolCallMessagePart[\"interrupt\"]>;\n} {\n if (part.approval && typeof part.approval.id === \"string\") {\n const { id, approved, reason, isAutomatic } = part.approval;\n return {\n approval: {\n id,\n ...(typeof approved === \"boolean\" && { approved }),\n ...(typeof reason === \"string\" && { reason }),\n ...(isAutomatic === true && { isAutomatic: true }),\n },\n };\n }\n\n if (toolStatus?.type === \"interrupt\") {\n return {\n interrupt: toolStatus.payload as NonNullable<\n ToolCallMessagePart[\"interrupt\"]\n >,\n };\n }\n\n return {};\n}\n\ntype MessageContent = Exclude<ThreadMessageLike[\"content\"], string>;\n\nfunction convertParts(\n message: UIMessage,\n metadata: AISDKMessageConverterMetadata,\n): MessageContent {\n if (!message.parts || message.parts.length === 0) {\n return [];\n }\n\n const converted = message.parts\n .filter(\n (p) =>\n p.type !== \"step-start\" &&\n (message.role !== \"user\" || p.type !== \"file\"),\n )\n .map((part) => {\n if (part.type === \"text\") {\n return {\n type: \"text\",\n text: part.text,\n } satisfies TextMessagePart;\n }\n\n if (part.type === \"reasoning\") {\n return {\n type: \"reasoning\",\n text: part.text,\n } satisfies ReasoningMessagePart;\n }\n\n if (isToolUIPart(part)) {\n const toolName = getToolName(part);\n const toolCallId = part.toolCallId;\n const argsKeyOrderCacheKey = `${message.id}:${toolCallId}`;\n\n const rawInput = part.input as ReadonlyJSONObject | null | undefined;\n let args: ReadonlyJSONObject;\n if (\n rawInput != null &&\n typeof rawInput === \"object\" &&\n !Array.isArray(rawInput)\n ) {\n args = rawInput;\n metadata.toolLastInputCache?.set(argsKeyOrderCacheKey, args);\n } else {\n args = metadata.toolLastInputCache?.get(argsKeyOrderCacheKey) ?? {};\n }\n\n let result: unknown;\n let modelContent: ToolCallMessagePart[\"modelContent\"];\n let isError = false;\n\n if (part.state === \"output-available\") {\n const unwrapped = unwrapModelContentEnvelope(part.output);\n result = unwrapped.result;\n modelContent = unwrapped.modelContent;\n } else if (part.state === \"output-error\") {\n isError = true;\n result = { error: part.errorText };\n } else if (part.state === \"output-denied\") {\n isError = true;\n result = {\n error:\n (part as { approval?: { reason?: string } }).approval?.reason ||\n \"Tool approval denied\",\n };\n }\n\n let argsText = stableStringifyToolArgs(\n metadata.toolArgsKeyOrderCache,\n argsKeyOrderCacheKey,\n args,\n );\n if (part.state === \"input-streaming\") {\n // strip closing delimiters added by the AI SDK's fix-json\n argsText = stripClosingDelimiters(argsText);\n } else {\n metadata.toolArgsKeyOrderCache?.delete(argsKeyOrderCacheKey);\n if (\n part.state === \"output-available\" ||\n part.state === \"output-error\" ||\n part.state === \"output-denied\"\n ) {\n metadata.toolLastInputCache?.delete(argsKeyOrderCacheKey);\n }\n }\n\n const toolStatus = metadata.toolStatuses?.[toolCallId];\n const mcpApp = extractMcpAppMetadata(\n part,\n metadata.mcpAppMetadataCache,\n );\n return {\n type: \"tool-call\",\n toolName,\n toolCallId,\n argsText,\n args,\n result,\n isError,\n ...(modelContent !== undefined && { modelContent }),\n ...(mcpApp && { mcp: { app: mcpApp } }),\n ...getToolApprovalAndInterrupt(part, toolStatus),\n } satisfies ToolCallMessagePart;\n }\n\n if (part.type === \"source-url\") {\n return {\n type: \"source\",\n sourceType: \"url\",\n id: part.sourceId,\n url: part.url,\n ...(part.title != null ? { title: part.title } : undefined),\n ...(part.providerMetadata != null\n ? {\n providerMetadata:\n part.providerMetadata as SourceProviderMetadata,\n }\n : undefined),\n } satisfies SourceMessagePart;\n }\n\n if (part.type === \"file\") {\n return {\n type: \"file\",\n data: part.url,\n mimeType: part.mediaType,\n ...(part.filename != null && { filename: part.filename }),\n } satisfies FileMessagePart;\n }\n\n if (part.type === \"source-document\") {\n return {\n type: \"source\",\n sourceType: \"document\",\n id: part.sourceId,\n title: part.title,\n mediaType: part.mediaType,\n ...(part.filename != null ? { filename: part.filename } : undefined),\n ...(part.providerMetadata != null\n ? {\n providerMetadata:\n part.providerMetadata as SourceProviderMetadata,\n }\n : undefined),\n } satisfies SourceMessagePart;\n }\n\n if (part.type.startsWith(\"data-\")) {\n return {\n type: \"data\",\n name: part.type.substring(5),\n data: (part as any).data,\n } satisfies DataMessagePart;\n }\n\n console.warn(`Unsupported message part type: ${part.type}`);\n return null;\n })\n .filter(Boolean) as MessageContent[number][];\n\n const seenToolCallIds = new Set<string>();\n return converted.filter((part) => {\n if (part.type === \"tool-call\" && part.toolCallId != null) {\n if (seenToolCallIds.has(part.toolCallId)) return false;\n seenToolCallIds.add(part.toolCallId);\n }\n return true;\n });\n}\n\nexport const AISDKMessageConverter = unstable_createMessageConverter(\n (message: UIMessage, metadata: AISDKMessageConverterMetadata) => {\n const createdAt = new Date();\n const content = convertParts(message, metadata);\n\n switch (message.role) {\n case \"user\":\n return {\n role: \"user\",\n id: message.id,\n createdAt,\n content,\n attachments: message.parts\n ?.filter((p) => p.type === \"file\")\n .map((part, idx) => ({\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 metadata: message.metadata as MessageMetadata,\n };\n\n case \"system\":\n case \"assistant\": {\n const timing = metadata.messageTiming?.[message.id];\n const isOptimistic =\n message.role === \"assistant\" &&\n message.id === metadata.optimisticMessageId;\n return {\n role: message.role,\n id: message.id,\n createdAt,\n content,\n metadata: {\n ...(message.metadata as MessageMetadata),\n ...(timing && { timing }),\n ...(isOptimistic && { isOptimistic: true }),\n },\n };\n }\n\n default:\n console.warn(`Unsupported message role: ${message.role}`);\n return [];\n }\n },\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"convertMessage.js","names":["unstable_createMessageConverter"],"sources":["../../../src/ui/utils/convertMessage.ts"],"sourcesContent":["import { isToolUIPart, getToolName, type UIMessage } from \"ai\";\nimport {\n createMessageConverter as unstable_createMessageConverter,\n type useExternalMessageConverter,\n} from \"@assistant-ui/core/react\";\nimport {\n isMcpAppUri,\n type ReasoningMessagePart,\n type ToolCallMessagePart,\n type TextMessagePart,\n type DataMessagePart,\n type SourceMessagePart,\n type SourceProviderMetadata,\n type FileMessagePart,\n type ThreadMessageLike,\n type McpAppMetadata,\n} from \"@assistant-ui/core\";\nimport {\n parsePartialJsonObject,\n type ReadonlyJSONObject,\n} from \"assistant-stream/utils\";\nimport { unwrapModelContentEnvelope } from \"../../modelContentEnvelope\";\n\ntype MessageMetadata = ThreadMessageLike[\"metadata\"];\nexport type AISDKMessageConverterMetadata =\n useExternalMessageConverter.Metadata & {\n toolArgsKeyOrderCache?: Map<string, Map<string, string[]>>;\n toolLastInputCache?: Map<string, ReadonlyJSONObject>;\n mcpAppMetadataCache?: Map<string, McpAppMetadata>;\n /** Id of the currently-streaming message, flagged optimistic (#4037). */\n optimisticMessageId?: string | undefined;\n };\n\nfunction stripClosingDelimiters(json: string): string {\n return json.replace(/[}\\]\"]+$/, \"\");\n}\n\nconst MCP_APP_METADATA_CACHE_MAX = 100;\n\nfunction extractMcpAppMetadata(\n part: unknown,\n cache: Map<string, McpAppMetadata> | undefined,\n): McpAppMetadata | undefined {\n if (!part || typeof part !== \"object\") return undefined;\n const meta = (part as { callProviderMetadata?: unknown })\n .callProviderMetadata;\n const mcp =\n meta && typeof meta === \"object\"\n ? (meta as { mcp?: unknown }).mcp\n : undefined;\n const app =\n mcp && typeof mcp === \"object\" ? (mcp as { app?: unknown }).app : undefined;\n let a: Record<string, unknown>;\n if (app && typeof app === \"object\") {\n a = app as Record<string, unknown>;\n } else {\n // MCP-UI tools (e.g. xmcp) surface the UI pointer as\n // result._meta[\"ui/resourceUri\"] rather than in callProviderMetadata.\n const output = (part as { output?: unknown }).output;\n const outMeta =\n output && typeof output === \"object\"\n ? (output as { _meta?: unknown })._meta\n : undefined;\n const uiResourceUri =\n outMeta && typeof outMeta === \"object\"\n ? (outMeta as Record<string, unknown>)[\"ui/resourceUri\"]\n : undefined;\n if (typeof uiResourceUri !== \"string\") return undefined;\n a = { resourceUri: uiResourceUri };\n }\n if (typeof a[\"resourceUri\"] !== \"string\") return undefined;\n if (!isMcpAppUri(a[\"resourceUri\"])) return undefined;\n const cached = cache?.get(a[\"resourceUri\"]);\n if (cached) {\n cache!.delete(a[\"resourceUri\"]);\n cache!.set(a[\"resourceUri\"], cached);\n return cached;\n }\n const out: { -readonly [K in keyof McpAppMetadata]: McpAppMetadata[K] } = {\n resourceUri: a[\"resourceUri\"],\n };\n if (typeof a[\"mimeType\"] === \"string\") out.mimeType = a[\"mimeType\"];\n if (Array.isArray(a[\"visibility\"])) {\n out.visibility = a[\"visibility\"].filter(\n (v): v is \"model\" | \"app\" => v === \"model\" || v === \"app\",\n );\n }\n if (cache) {\n if (cache.size >= MCP_APP_METADATA_CACHE_MAX) {\n const oldest = cache.keys().next().value;\n if (oldest !== undefined) cache.delete(oldest);\n }\n cache.set(a[\"resourceUri\"], out);\n }\n return out;\n}\n\nconst hasOwn = (value: object, key: string) => Object.hasOwn(value, key);\n\nconst stabilizeToolArgsValue = (\n value: unknown,\n path: string,\n keyOrderByPath: Map<string, string[]>,\n): unknown => {\n if (Array.isArray(value)) {\n return value.map((item, idx) =>\n stabilizeToolArgsValue(item, `${path}[${idx}]`, keyOrderByPath),\n );\n }\n\n if (value && typeof value === \"object\") {\n const record = value as Record<string, unknown>;\n const currentKeys = Object.keys(record);\n const previousOrder = keyOrderByPath.get(path) ?? [];\n const previousOrderSet = new Set(previousOrder);\n const nextOrder = [\n ...previousOrder.filter((key) => hasOwn(record, key)),\n ...currentKeys.filter((key) => !previousOrderSet.has(key)),\n ];\n keyOrderByPath.set(path, nextOrder);\n\n return Object.fromEntries(\n nextOrder.map((key) => [\n key,\n stabilizeToolArgsValue(record[key], `${path}.${key}`, keyOrderByPath),\n ]),\n );\n }\n\n return value;\n};\n\nfunction stableStringifyToolArgs(\n keyOrderCache: Map<string, Map<string, string[]>> | undefined,\n cacheKey: string,\n args: ReadonlyJSONObject,\n): string {\n const keyOrderByPath = keyOrderCache?.get(cacheKey) ?? new Map();\n keyOrderCache?.set(cacheKey, keyOrderByPath);\n\n const stableArgs = stabilizeToolArgsValue(\n args,\n \"$\",\n keyOrderByPath,\n ) as ReadonlyJSONObject;\n return JSON.stringify(stableArgs);\n}\n\nfunction getToolApprovalAndInterrupt(\n part: {\n approval?:\n | {\n id: string;\n approved?: boolean;\n reason?: string;\n isAutomatic?: boolean;\n }\n | undefined;\n },\n toolStatus: { type: string; payload?: unknown } | undefined,\n): {\n approval?: NonNullable<ToolCallMessagePart[\"approval\"]>;\n interrupt?: NonNullable<ToolCallMessagePart[\"interrupt\"]>;\n} {\n if (part.approval && typeof part.approval.id === \"string\") {\n const { id, approved, reason, isAutomatic } = part.approval;\n return {\n approval: {\n id,\n ...(typeof approved === \"boolean\" && { approved }),\n ...(typeof reason === \"string\" && { reason }),\n ...(isAutomatic === true && { isAutomatic: true }),\n },\n };\n }\n\n if (toolStatus?.type === \"interrupt\") {\n return {\n interrupt: toolStatus.payload as NonNullable<\n ToolCallMessagePart[\"interrupt\"]\n >,\n };\n }\n\n return {};\n}\n\ntype MessageContent = Exclude<ThreadMessageLike[\"content\"], string>;\n\nfunction convertParts(\n message: UIMessage,\n metadata: AISDKMessageConverterMetadata,\n): MessageContent {\n if (!message.parts || message.parts.length === 0) {\n return [];\n }\n\n const converted = message.parts\n .filter(\n (p) =>\n p.type !== \"step-start\" &&\n (message.role !== \"user\" || p.type !== \"file\"),\n )\n .map((part) => {\n if (part.type === \"text\") {\n return {\n type: \"text\",\n text: part.text,\n } satisfies TextMessagePart;\n }\n\n if (part.type === \"reasoning\") {\n return {\n type: \"reasoning\",\n text: part.text,\n } satisfies ReasoningMessagePart;\n }\n\n if (isToolUIPart(part)) {\n const toolName = getToolName(part);\n const toolCallId = part.toolCallId;\n const argsKeyOrderCacheKey = `${message.id}:${toolCallId}`;\n\n const rawInput = part.input as ReadonlyJSONObject | null | undefined;\n let args: ReadonlyJSONObject;\n if (\n rawInput != null &&\n typeof rawInput === \"object\" &&\n !Array.isArray(rawInput)\n ) {\n args = rawInput;\n metadata.toolLastInputCache?.set(argsKeyOrderCacheKey, args);\n } else {\n args = metadata.toolLastInputCache?.get(argsKeyOrderCacheKey) ?? {};\n }\n\n let result: unknown;\n let modelContent: ToolCallMessagePart[\"modelContent\"];\n let isError = false;\n\n if (part.state === \"output-available\") {\n const unwrapped = unwrapModelContentEnvelope(part.output);\n result = unwrapped.result;\n modelContent = unwrapped.modelContent;\n } else if (part.state === \"output-error\") {\n isError = true;\n result = { error: part.errorText };\n } else if (part.state === \"output-denied\") {\n isError = true;\n result = {\n error:\n (part as { approval?: { reason?: string } }).approval?.reason ||\n \"Tool approval denied\",\n };\n }\n\n let argsText = stableStringifyToolArgs(\n metadata.toolArgsKeyOrderCache,\n argsKeyOrderCacheKey,\n args,\n );\n if (part.state === \"input-streaming\") {\n // strip closing delimiters added by the AI SDK's fix-json\n argsText = stripClosingDelimiters(argsText);\n // Re-parse so args carries the partial-JSON meta that marks which\n // field is still mid-arrival, like every argsText-based runtime.\n // The key-order cache appends new keys last, so the trailing field\n // of the stripped text is the streaming frontier.\n args = parsePartialJsonObject(argsText) ?? args;\n } else {\n metadata.toolArgsKeyOrderCache?.delete(argsKeyOrderCacheKey);\n if (\n part.state === \"output-available\" ||\n part.state === \"output-error\" ||\n part.state === \"output-denied\"\n ) {\n metadata.toolLastInputCache?.delete(argsKeyOrderCacheKey);\n }\n }\n\n const toolStatus = metadata.toolStatuses?.[toolCallId];\n const mcpApp = extractMcpAppMetadata(\n part,\n metadata.mcpAppMetadataCache,\n );\n return {\n type: \"tool-call\",\n toolName,\n toolCallId,\n argsText,\n args,\n result,\n isError,\n ...(modelContent !== undefined && { modelContent }),\n ...(mcpApp && { mcp: { app: mcpApp } }),\n ...getToolApprovalAndInterrupt(part, toolStatus),\n } satisfies ToolCallMessagePart;\n }\n\n if (part.type === \"source-url\") {\n return {\n type: \"source\",\n sourceType: \"url\",\n id: part.sourceId,\n url: part.url,\n ...(part.title != null ? { title: part.title } : undefined),\n ...(part.providerMetadata != null\n ? {\n providerMetadata:\n part.providerMetadata as SourceProviderMetadata,\n }\n : undefined),\n } satisfies SourceMessagePart;\n }\n\n if (part.type === \"file\") {\n return {\n type: \"file\",\n data: part.url,\n mimeType: part.mediaType,\n ...(part.filename != null && { filename: part.filename }),\n } satisfies FileMessagePart;\n }\n\n if (part.type === \"source-document\") {\n return {\n type: \"source\",\n sourceType: \"document\",\n id: part.sourceId,\n title: part.title,\n mediaType: part.mediaType,\n ...(part.filename != null ? { filename: part.filename } : undefined),\n ...(part.providerMetadata != null\n ? {\n providerMetadata:\n part.providerMetadata as SourceProviderMetadata,\n }\n : undefined),\n } satisfies SourceMessagePart;\n }\n\n if (part.type.startsWith(\"data-\")) {\n return {\n type: \"data\",\n name: part.type.substring(5),\n data: (part as any).data,\n } satisfies DataMessagePart;\n }\n\n console.warn(`Unsupported message part type: ${part.type}`);\n return null;\n })\n .filter(Boolean) as MessageContent[number][];\n\n const seenToolCallIds = new Set<string>();\n return converted.filter((part) => {\n if (part.type === \"tool-call\" && part.toolCallId != null) {\n if (seenToolCallIds.has(part.toolCallId)) return false;\n seenToolCallIds.add(part.toolCallId);\n }\n return true;\n });\n}\n\nexport const AISDKMessageConverter = unstable_createMessageConverter(\n (message: UIMessage, metadata: AISDKMessageConverterMetadata) => {\n const createdAt = new Date();\n const content = convertParts(message, metadata);\n\n switch (message.role) {\n case \"user\":\n return {\n role: \"user\",\n id: message.id,\n createdAt,\n content,\n attachments: message.parts\n ?.filter((p) => p.type === \"file\")\n .map((part, idx) => ({\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 metadata: message.metadata as MessageMetadata,\n };\n\n case \"system\":\n case \"assistant\": {\n const timing = metadata.messageTiming?.[message.id];\n const isOptimistic =\n message.role === \"assistant\" &&\n message.id === metadata.optimisticMessageId;\n return {\n role: message.role,\n id: message.id,\n createdAt,\n content,\n metadata: {\n ...(message.metadata as MessageMetadata),\n ...(timing && { timing }),\n ...(isOptimistic && { isOptimistic: true }),\n },\n };\n }\n\n default:\n console.warn(`Unsupported message role: ${message.role}`);\n return [];\n }\n },\n);\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sliceMessagesUntil.js","names":[],"sources":["../../../src/ui/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 \"useVercelAIThreadState: Message not found. 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,MAAa,sBACX,UACA,cACG;CACH,IAAI,aAAa,MAAM,OAAO,CAAC;CAE/B,IAAI,aAAa,SAAS,WAAW,MAAM,EAAE,OAAO,SAAS;CAC7D,IAAI,eAAe,IACjB,MAAM,IAAI,MACR,4FACF;CAEF,OAAO,SAAS,aAAa,
|
|
1
|
+
{"version":3,"file":"sliceMessagesUntil.js","names":[],"sources":["../../../src/ui/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 \"useVercelAIThreadState: Message not found. 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,MAAa,sBACX,UACA,cACG;CACH,IAAI,aAAa,MAAM,OAAO,CAAC;CAE/B,IAAI,aAAa,SAAS,WAAW,MAAM,EAAE,OAAO,SAAS;CAC7D,IAAI,eAAe,IACjB,MAAM,IAAI,MACR,4FACF;CAEF,OAAO,SAAS,aAAa,EAAE,EAAE,SAAS,aACxC;CAGF,OAAO,SAAS,MAAM,GAAG,aAAa,CAAC;AACzC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toCreateMessage.js","names":[],"sources":["../../../src/ui/utils/toCreateMessage.ts"],"sourcesContent":["import type { AppendMessage } from \"@assistant-ui/core\";\nimport type {\n CreateUIMessage,\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 case \"data\":\n return {\n type: `data-${part.name}`,\n data: part.data,\n };\n default:\n throw new Error(`Unsupported part type: ${part.type}`);\n }\n });\n\n return {\n role: message.role,\n parts,\n metadata: message.metadata,\n } satisfies CreateUIMessage<UIMessage> as CreateUIMessage<UI_MESSAGE>;\n};\n"],"mappings":";AASA,MAAa,mBACX,YACgC;CAWhC,MAAM,QAAQ,CATZ,GAAG,QAAQ,QAAQ,QAAQ,MAAM,EAAE,SAAS,MAAM,GAClD,GAAI,QAAQ,aAAa,SAAS,MAChC,EAAE,QAAQ,KAAK,OAAO;EACpB,GAAG;EACH,UAAU,EAAE;CACd,EAAE,CACJ,KAAK,CAAC,CAGe,
|
|
1
|
+
{"version":3,"file":"toCreateMessage.js","names":[],"sources":["../../../src/ui/utils/toCreateMessage.ts"],"sourcesContent":["import type { AppendMessage } from \"@assistant-ui/core\";\nimport type {\n CreateUIMessage,\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 case \"data\":\n return {\n type: `data-${part.name}`,\n data: part.data,\n };\n default:\n throw new Error(`Unsupported part type: ${part.type}`);\n }\n });\n\n return {\n role: message.role,\n parts,\n metadata: message.metadata,\n } satisfies CreateUIMessage<UIMessage> as CreateUIMessage<UI_MESSAGE>;\n};\n"],"mappings":";AASA,MAAa,mBACX,YACgC;CAWhC,MAAM,QAAQ,CATZ,GAAG,QAAQ,QAAQ,QAAQ,MAAM,EAAE,SAAS,MAAM,GAClD,GAAI,QAAQ,aAAa,SAAS,MAChC,EAAE,QAAQ,KAAK,OAAO;EACpB,GAAG;EACH,UAAU,EAAE;CACd,EAAE,CACJ,KAAK,CAAC,CAGe,CAAC,CAAC,KAAK,SAA8C;EAC1E,QAAQ,KAAK,MAAb;GACE,KAAK,QACH,OAAO;IACL,MAAM;IACN,MAAM,KAAK;GACb;GACF,KAAK,SACH,OAAO;IACL,MAAM;IACN,KAAK,KAAK;IACV,GAAI,KAAK,YAAY,EAAE,UAAU,KAAK,SAAS;IAC/C,WAAW;GACb;GACF,KAAK,QACH,OAAO;IACL,MAAM;IACN,KAAK,KAAK;IACV,WAAW,KAAK;IAChB,GAAI,KAAK,YAAY,EAAE,UAAU,KAAK,SAAS;GACjD;GACF,KAAK,QACH,OAAO;IACL,MAAM,QAAQ,KAAK;IACnB,MAAM,KAAK;GACb;GACF,SACE,MAAM,IAAI,MAAM,0BAA0B,KAAK,MAAM;EACzD;CACF,CAAC;CAED,OAAO;EACL,MAAM,QAAQ;EACd;EACA,UAAU,QAAQ;CACpB;AACF"}
|
package/dist/usage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.js","names":[],"sources":["../src/usage.ts"],"sourcesContent":["/// <reference types=\"@assistant-ui/core/react\" />\nimport { useAuiState } from \"@assistant-ui/store\";\n\nexport type ThreadTokenUsage = {\n totalTokens?: number;\n inputTokens?: number;\n outputTokens?: number;\n reasoningTokens?: number;\n cachedInputTokens?: number;\n};\n\nexport interface TokenUsageExtractableMessage {\n role?: string;\n metadata?: unknown;\n}\n\ntype UsageRecord = Record<string, unknown>;\n\nconst USAGE_KEYS = [\n \"inputTokens\",\n \"outputTokens\",\n \"reasoningTokens\",\n \"cachedInputTokens\",\n \"totalTokens\",\n] as const satisfies (keyof ThreadTokenUsage)[];\n\nfunction asRecord(value: unknown): UsageRecord | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value))\n return undefined;\n return value as UsageRecord;\n}\n\nfunction asPositiveTokenCount(value: unknown): number | undefined {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) {\n return undefined;\n }\n return value;\n}\n\nfunction computeTotalTokens(usage: ThreadTokenUsage): number | undefined {\n if (usage.totalTokens !== undefined) return usage.totalTokens;\n if (usage.inputTokens !== undefined && usage.outputTokens !== undefined) {\n return usage.inputTokens + usage.outputTokens;\n }\n return undefined;\n}\n\nfunction normalizeUsage(value: unknown): ThreadTokenUsage | undefined {\n const record = asRecord(value);\n if (!record) return undefined;\n\n const result: ThreadTokenUsage = {};\n let hasFields = false;\n for (const key of USAGE_KEYS) {\n const count = asPositiveTokenCount(record[key]);\n if (count !== undefined) {\n result[key] = count;\n hasFields = true;\n }\n }\n return hasFields ? result : undefined;\n}\n\nfunction withComputedTotal(\n usage: ThreadTokenUsage,\n): ThreadTokenUsage | undefined {\n const totalTokens = computeTotalTokens(usage);\n return { ...usage, ...(totalTokens !== undefined && { totalTokens }) };\n}\n\nfunction usageFromSteps(value: unknown): ThreadTokenUsage | undefined {\n const steps = Array.isArray(value) ? value : [];\n\n const sums: Record<string, number> = {};\n const present: Record<string, boolean> = {};\n let stepsWithUsage = 0;\n let stepsWithComputableTotal = 0;\n\n for (const step of steps) {\n const usage = normalizeUsage(asRecord(step)?.usage);\n if (!usage) continue;\n stepsWithUsage++;\n\n const stepTotal = computeTotalTokens(usage);\n if (stepTotal !== undefined) {\n sums.totalTokens = (sums.totalTokens ?? 0) + stepTotal;\n stepsWithComputableTotal++;\n }\n\n for (const key of USAGE_KEYS) {\n if (key === \"totalTokens\") continue;\n if (usage[key] !== undefined) {\n sums[key] = (sums[key] ?? 0) + usage[key];\n present[key] = true;\n }\n }\n }\n\n if (stepsWithUsage === 0) return undefined;\n\n const result: ThreadTokenUsage = {};\n if (stepsWithComputableTotal === stepsWithUsage) {\n result.totalTokens = sums.totalTokens!;\n }\n for (const key of USAGE_KEYS) {\n if (key === \"totalTokens\") continue;\n if (present[key]) {\n result[key] = sums[key]!;\n }\n }\n return result;\n}\n\nexport function getThreadMessageTokenUsage(\n message: TokenUsageExtractableMessage | undefined,\n): ThreadTokenUsage | undefined {\n if (!message || message.role !== \"assistant\") return undefined;\n\n const metadata = asRecord(message.metadata);\n if (!metadata) return undefined;\n\n const topLevelUsage = normalizeUsage(metadata.usage);\n if (topLevelUsage) return withComputedTotal(topLevelUsage);\n\n const legacyUsage = normalizeUsage(asRecord(metadata.custom)?.usage);\n if (legacyUsage) return withComputedTotal(legacyUsage);\n\n return usageFromSteps(metadata.steps);\n}\n\nexport function getLatestThreadTokenUsage(\n messages: readonly TokenUsageExtractableMessage[] | undefined,\n): ThreadTokenUsage | undefined {\n return getThreadMessageTokenUsage(findLatestMessageWithUsage(messages));\n}\n\nfunction findLatestMessageWithUsage(\n messages: readonly TokenUsageExtractableMessage[] | undefined,\n): TokenUsageExtractableMessage | undefined {\n if (!messages) return undefined;\n\n for (let idx = messages.length - 1; idx >= 0; idx -= 1) {\n const message = messages[idx];\n if (getThreadMessageTokenUsage(message)) {\n return message;\n }\n }\n\n return undefined;\n}\n\nexport function useThreadTokenUsage(): ThreadTokenUsage | undefined {\n const msg = useAuiState((s) => findLatestMessageWithUsage(s.thread.messages));\n return getThreadMessageTokenUsage(msg);\n}\n"],"mappings":";;AAkBA,MAAM,aAAa;CACjB;CACA;CACA;CACA;CACA;AACF;AAEA,SAAS,SAAS,OAAyC;CACzD,IAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAC5D,OAAO,KAAA;CACT,OAAO;AACT;AAEA,SAAS,qBAAqB,OAAoC;CAChE,IAAI,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,KAAK,QAAQ,GAClE;CAEF,OAAO;AACT;AAEA,SAAS,mBAAmB,OAA6C;CACvE,IAAI,MAAM,gBAAgB,KAAA,GAAW,OAAO,MAAM;CAClD,IAAI,MAAM,gBAAgB,KAAA,KAAa,MAAM,iBAAiB,KAAA,GAC5D,OAAO,MAAM,cAAc,MAAM;AAGrC;AAEA,SAAS,eAAe,OAA8C;CACpE,MAAM,SAAS,SAAS,KAAK;CAC7B,IAAI,CAAC,QAAQ,OAAO,KAAA;CAEpB,MAAM,SAA2B,CAAC;CAClC,IAAI,YAAY;CAChB,KAAK,MAAM,OAAO,YAAY;EAC5B,MAAM,QAAQ,qBAAqB,OAAO,IAAI;EAC9C,IAAI,UAAU,KAAA,GAAW;GACvB,OAAO,OAAO;GACd,YAAY;EACd;CACF;CACA,OAAO,YAAY,SAAS,KAAA;AAC9B;AAEA,SAAS,kBACP,OAC8B;CAC9B,MAAM,cAAc,mBAAmB,KAAK;CAC5C,OAAO;EAAE,GAAG;EAAO,GAAI,gBAAgB,KAAA,KAAa,EAAE,YAAY;CAAG;AACvE;AAEA,SAAS,eAAe,OAA8C;CACpE,MAAM,QAAQ,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC;CAE9C,MAAM,OAA+B,CAAC;CACtC,MAAM,UAAmC,CAAC;CAC1C,IAAI,iBAAiB;CACrB,IAAI,2BAA2B;CAE/B,KAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,QAAQ,eAAe,SAAS,IAAI,
|
|
1
|
+
{"version":3,"file":"usage.js","names":[],"sources":["../src/usage.ts"],"sourcesContent":["/// <reference types=\"@assistant-ui/core/react\" />\nimport { useAuiState } from \"@assistant-ui/store\";\n\nexport type ThreadTokenUsage = {\n totalTokens?: number;\n inputTokens?: number;\n outputTokens?: number;\n reasoningTokens?: number;\n cachedInputTokens?: number;\n};\n\nexport interface TokenUsageExtractableMessage {\n role?: string;\n metadata?: unknown;\n}\n\ntype UsageRecord = Record<string, unknown>;\n\nconst USAGE_KEYS = [\n \"inputTokens\",\n \"outputTokens\",\n \"reasoningTokens\",\n \"cachedInputTokens\",\n \"totalTokens\",\n] as const satisfies (keyof ThreadTokenUsage)[];\n\nfunction asRecord(value: unknown): UsageRecord | undefined {\n if (!value || typeof value !== \"object\" || Array.isArray(value))\n return undefined;\n return value as UsageRecord;\n}\n\nfunction asPositiveTokenCount(value: unknown): number | undefined {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) {\n return undefined;\n }\n return value;\n}\n\nfunction computeTotalTokens(usage: ThreadTokenUsage): number | undefined {\n if (usage.totalTokens !== undefined) return usage.totalTokens;\n if (usage.inputTokens !== undefined && usage.outputTokens !== undefined) {\n return usage.inputTokens + usage.outputTokens;\n }\n return undefined;\n}\n\nfunction normalizeUsage(value: unknown): ThreadTokenUsage | undefined {\n const record = asRecord(value);\n if (!record) return undefined;\n\n const result: ThreadTokenUsage = {};\n let hasFields = false;\n for (const key of USAGE_KEYS) {\n const count = asPositiveTokenCount(record[key]);\n if (count !== undefined) {\n result[key] = count;\n hasFields = true;\n }\n }\n return hasFields ? result : undefined;\n}\n\nfunction withComputedTotal(\n usage: ThreadTokenUsage,\n): ThreadTokenUsage | undefined {\n const totalTokens = computeTotalTokens(usage);\n return { ...usage, ...(totalTokens !== undefined && { totalTokens }) };\n}\n\nfunction usageFromSteps(value: unknown): ThreadTokenUsage | undefined {\n const steps = Array.isArray(value) ? value : [];\n\n const sums: Record<string, number> = {};\n const present: Record<string, boolean> = {};\n let stepsWithUsage = 0;\n let stepsWithComputableTotal = 0;\n\n for (const step of steps) {\n const usage = normalizeUsage(asRecord(step)?.usage);\n if (!usage) continue;\n stepsWithUsage++;\n\n const stepTotal = computeTotalTokens(usage);\n if (stepTotal !== undefined) {\n sums.totalTokens = (sums.totalTokens ?? 0) + stepTotal;\n stepsWithComputableTotal++;\n }\n\n for (const key of USAGE_KEYS) {\n if (key === \"totalTokens\") continue;\n if (usage[key] !== undefined) {\n sums[key] = (sums[key] ?? 0) + usage[key];\n present[key] = true;\n }\n }\n }\n\n if (stepsWithUsage === 0) return undefined;\n\n const result: ThreadTokenUsage = {};\n if (stepsWithComputableTotal === stepsWithUsage) {\n result.totalTokens = sums.totalTokens!;\n }\n for (const key of USAGE_KEYS) {\n if (key === \"totalTokens\") continue;\n if (present[key]) {\n result[key] = sums[key]!;\n }\n }\n return result;\n}\n\nexport function getThreadMessageTokenUsage(\n message: TokenUsageExtractableMessage | undefined,\n): ThreadTokenUsage | undefined {\n if (!message || message.role !== \"assistant\") return undefined;\n\n const metadata = asRecord(message.metadata);\n if (!metadata) return undefined;\n\n const topLevelUsage = normalizeUsage(metadata.usage);\n if (topLevelUsage) return withComputedTotal(topLevelUsage);\n\n const legacyUsage = normalizeUsage(asRecord(metadata.custom)?.usage);\n if (legacyUsage) return withComputedTotal(legacyUsage);\n\n return usageFromSteps(metadata.steps);\n}\n\nexport function getLatestThreadTokenUsage(\n messages: readonly TokenUsageExtractableMessage[] | undefined,\n): ThreadTokenUsage | undefined {\n return getThreadMessageTokenUsage(findLatestMessageWithUsage(messages));\n}\n\nfunction findLatestMessageWithUsage(\n messages: readonly TokenUsageExtractableMessage[] | undefined,\n): TokenUsageExtractableMessage | undefined {\n if (!messages) return undefined;\n\n for (let idx = messages.length - 1; idx >= 0; idx -= 1) {\n const message = messages[idx];\n if (getThreadMessageTokenUsage(message)) {\n return message;\n }\n }\n\n return undefined;\n}\n\nexport function useThreadTokenUsage(): ThreadTokenUsage | undefined {\n const msg = useAuiState((s) => findLatestMessageWithUsage(s.thread.messages));\n return getThreadMessageTokenUsage(msg);\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@assistant-ui/react-ai-sdk",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.35",
|
|
4
4
|
"description": "Vercel AI SDK adapter for assistant-ui",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-sdk",
|
|
@@ -15,13 +15,29 @@
|
|
|
15
15
|
"author": "AgentbaseAI Inc.",
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"type": "module",
|
|
18
|
+
"imports": {
|
|
19
|
+
"#mcp-stdio": {
|
|
20
|
+
"types": "./src/mcp-stdio.node.ts",
|
|
21
|
+
"react-native": "./dist/mcp-stdio.unsupported.js",
|
|
22
|
+
"edge-light": "./dist/mcp-stdio.unsupported.js",
|
|
23
|
+
"workerd": "./dist/mcp-stdio.unsupported.js",
|
|
24
|
+
"browser": "./dist/mcp-stdio.unsupported.js",
|
|
25
|
+
"node": "./dist/mcp-stdio.node.js",
|
|
26
|
+
"default": "./dist/mcp-stdio.unsupported.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
18
29
|
"exports": {
|
|
19
30
|
".": {
|
|
31
|
+
"react-native": {
|
|
32
|
+
"types": "./dist/index.native.d.ts",
|
|
33
|
+
"default": "./dist/index.native.js"
|
|
34
|
+
},
|
|
20
35
|
"types": "./dist/index.d.ts",
|
|
21
36
|
"default": "./dist/index.js"
|
|
22
37
|
}
|
|
23
38
|
},
|
|
24
39
|
"main": "./dist/index.js",
|
|
40
|
+
"react-native": "./dist/index.native.js",
|
|
25
41
|
"types": "./dist/index.d.ts",
|
|
26
42
|
"files": [
|
|
27
43
|
"dist",
|
|
@@ -30,12 +46,13 @@
|
|
|
30
46
|
],
|
|
31
47
|
"sideEffects": false,
|
|
32
48
|
"dependencies": {
|
|
33
|
-
"@ai-sdk/mcp": "^1.0.
|
|
34
|
-
"@ai-sdk/react": "^3.0.
|
|
35
|
-
"@assistant-ui/core": "^0.2.
|
|
36
|
-
"@assistant-ui/store": "^0.2.
|
|
37
|
-
"ai": "^6.0.
|
|
38
|
-
"assistant-cloud": "*"
|
|
49
|
+
"@ai-sdk/mcp": "^1.0.46",
|
|
50
|
+
"@ai-sdk/react": "^3.0.199",
|
|
51
|
+
"@assistant-ui/core": "^0.2.14",
|
|
52
|
+
"@assistant-ui/store": "^0.2.16",
|
|
53
|
+
"ai": "^6.0.197",
|
|
54
|
+
"assistant-cloud": "*",
|
|
55
|
+
"assistant-stream": "^0.3.21"
|
|
39
56
|
},
|
|
40
57
|
"peerDependencies": {
|
|
41
58
|
"@types/react": "*",
|
|
@@ -49,13 +66,12 @@
|
|
|
49
66
|
"devDependencies": {
|
|
50
67
|
"@testing-library/react": "^16.3.2",
|
|
51
68
|
"@types/json-schema": "^7.0.15",
|
|
52
|
-
"@types/react": "^19.2.
|
|
69
|
+
"@types/react": "^19.2.17",
|
|
53
70
|
"@types/react-dom": "^19.2.3",
|
|
54
71
|
"jsdom": "^29.1.1",
|
|
55
|
-
"react": "^19.2.
|
|
56
|
-
"vitest": "^4.1.
|
|
57
|
-
"assistant-
|
|
58
|
-
"@assistant-ui/x-buildutils": "0.0.11"
|
|
72
|
+
"react": "^19.2.7",
|
|
73
|
+
"vitest": "^4.1.8",
|
|
74
|
+
"@assistant-ui/x-buildutils": "0.0.12"
|
|
59
75
|
},
|
|
60
76
|
"publishConfig": {
|
|
61
77
|
"access": "public",
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/// <reference types="@assistant-ui/core/react" />
|
|
2
|
+
|
|
3
|
+
export { useAISDKRuntime } from "./ui/use-chat/useAISDKRuntime";
|
|
4
|
+
export { useChatRuntime } from "./ui/use-chat/useChatRuntime";
|
|
5
|
+
export type { UseChatRuntimeOptions } from "./ui/use-chat/useChatRuntime";
|
|
6
|
+
export { AssistantChatTransport } from "./ui/use-chat/AssistantChatTransport";
|
|
7
|
+
export {
|
|
8
|
+
RESUMABLE_STREAM_ID_HEADER,
|
|
9
|
+
createResumableSessionStorage,
|
|
10
|
+
} from "./ui/resumable";
|
|
11
|
+
export type {
|
|
12
|
+
AssistantChatResumableOptions,
|
|
13
|
+
ResumableClientStorage,
|
|
14
|
+
} from "./ui/resumable";
|
|
15
|
+
export { frontendTools } from "./frontendTools";
|
|
16
|
+
export { injectQuoteContext } from "./injectQuoteContext";
|
|
17
|
+
export type { ThreadTokenUsage, TokenUsageExtractableMessage } from "./usage";
|
|
18
|
+
export { getThreadMessageTokenUsage, useThreadTokenUsage } from "./usage";
|