@assistant-ui/react-ai-sdk 1.3.26 → 1.3.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/dist/frontendTools.d.ts +9 -5
  2. package/dist/frontendTools.d.ts.map +1 -1
  3. package/dist/frontendTools.js +36 -35
  4. package/dist/frontendTools.js.map +1 -1
  5. package/dist/index.d.ts +9 -11
  6. package/dist/index.js +9 -10
  7. package/dist/injectQuoteContext.d.ts +6 -2
  8. package/dist/injectQuoteContext.d.ts.map +1 -1
  9. package/dist/injectQuoteContext.js +46 -53
  10. package/dist/injectQuoteContext.js.map +1 -1
  11. package/dist/modelContentEnvelope.d.ts +12 -10
  12. package/dist/modelContentEnvelope.d.ts.map +1 -1
  13. package/dist/modelContentEnvelope.js +17 -15
  14. package/dist/modelContentEnvelope.js.map +1 -1
  15. package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts +141 -0
  16. package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts.map +1 -0
  17. package/dist/packages/assistant-stream/dist/core/AssistantStream.d.ts +1 -0
  18. package/dist/packages/assistant-stream/dist/core/AssistantStreamChunk.d.ts +1 -0
  19. package/dist/packages/assistant-stream/dist/core/accumulators/AssistantMessageStream.d.ts +1 -0
  20. package/dist/packages/assistant-stream/dist/core/accumulators/assistant-message-accumulator.d.ts +1 -0
  21. package/dist/packages/assistant-stream/dist/core/modules/assistant-stream.d.ts +1 -0
  22. package/dist/packages/assistant-stream/dist/core/modules/text.d.ts +1 -0
  23. package/dist/packages/assistant-stream/dist/core/modules/tool-call.d.ts +1 -0
  24. package/dist/packages/assistant-stream/dist/core/serialization/PlainText.d.ts +1 -0
  25. package/dist/packages/assistant-stream/dist/core/serialization/assistant-transport/AssistantTransport.d.ts +1 -0
  26. package/dist/packages/assistant-stream/dist/core/serialization/data-stream/DataStream.d.ts +1 -0
  27. package/dist/packages/assistant-stream/dist/core/serialization/ui-message-stream/UIMessageStream.d.ts +1 -0
  28. package/dist/packages/assistant-stream/dist/core/tool/ToolExecutionStream.d.ts +1 -0
  29. package/dist/packages/assistant-stream/dist/core/tool/schema-utils.d.ts +1 -0
  30. package/dist/packages/assistant-stream/dist/core/tool/schema-utils.js +50 -0
  31. package/dist/packages/assistant-stream/dist/core/tool/schema-utils.js.map +1 -0
  32. package/dist/packages/assistant-stream/dist/core/tool/tool-types.d.ts +43 -0
  33. package/dist/packages/assistant-stream/dist/core/tool/tool-types.d.ts.map +1 -0
  34. package/dist/packages/assistant-stream/dist/core/tool/toolResultStream.d.ts +1 -0
  35. package/dist/packages/assistant-stream/dist/core/utils/stream/AssistantMetaTransformStream.d.ts +1 -0
  36. package/dist/packages/assistant-stream/dist/core/utils/stream/AssistantTransformStream.d.ts +1 -0
  37. package/dist/packages/assistant-stream/dist/core/utils/types.d.ts +1 -0
  38. package/dist/packages/assistant-stream/dist/index.d.ts +1 -0
  39. package/dist/packages/assistant-stream/dist/resumable/createResumableAssistantStreamResponse.d.ts +6 -0
  40. package/dist/packages/assistant-stream/dist/resumable/createResumableAssistantStreamResponse.d.ts.map +1 -0
  41. package/dist/packages/assistant-stream/dist/resumable/createResumableAssistantStreamResponse.js +6 -0
  42. package/dist/packages/assistant-stream/dist/resumable/createResumableAssistantStreamResponse.js.map +1 -0
  43. package/dist/packages/assistant-stream/dist/resumable/index.d.ts +1 -0
  44. package/dist/packages/assistant-stream/dist/utils/json/json-value.d.ts +10 -0
  45. package/dist/packages/assistant-stream/dist/utils/json/json-value.d.ts.map +1 -0
  46. package/dist/packages/assistant-stream/dist/utils.d.ts +1 -0
  47. package/dist/ui/adapters/aiSDKFormatAdapter.d.ts +8 -4
  48. package/dist/ui/adapters/aiSDKFormatAdapter.d.ts.map +1 -1
  49. package/dist/ui/adapters/aiSDKFormatAdapter.js +24 -20
  50. package/dist/ui/adapters/aiSDKFormatAdapter.js.map +1 -1
  51. package/dist/ui/getVercelAIMessages.d.ts +7 -3
  52. package/dist/ui/getVercelAIMessages.d.ts.map +1 -1
  53. package/dist/ui/getVercelAIMessages.js +7 -3
  54. package/dist/ui/getVercelAIMessages.js.map +1 -1
  55. package/dist/ui/resumable.d.ts +18 -15
  56. package/dist/ui/resumable.d.ts.map +1 -1
  57. package/dist/ui/resumable.js +21 -20
  58. package/dist/ui/resumable.js.map +1 -1
  59. package/dist/ui/use-chat/AssistantChatTransport.d.ts +17 -14
  60. package/dist/ui/use-chat/AssistantChatTransport.d.ts.map +1 -1
  61. package/dist/ui/use-chat/AssistantChatTransport.js +98 -108
  62. package/dist/ui/use-chat/AssistantChatTransport.js.map +1 -1
  63. package/dist/ui/use-chat/useAISDKRuntime.d.ts +43 -33
  64. package/dist/ui/use-chat/useAISDKRuntime.d.ts.map +1 -1
  65. package/dist/ui/use-chat/useAISDKRuntime.js +184 -204
  66. package/dist/ui/use-chat/useAISDKRuntime.js.map +1 -1
  67. package/dist/ui/use-chat/useChatRuntime.d.ts +19 -12
  68. package/dist/ui/use-chat/useChatRuntime.d.ts.map +1 -1
  69. package/dist/ui/use-chat/useChatRuntime.js +60 -81
  70. package/dist/ui/use-chat/useChatRuntime.js.map +1 -1
  71. package/dist/ui/use-chat/useExternalHistory.d.ts +8 -4
  72. package/dist/ui/use-chat/useExternalHistory.d.ts.map +1 -1
  73. package/dist/ui/use-chat/useExternalHistory.js +178 -200
  74. package/dist/ui/use-chat/useExternalHistory.js.map +1 -1
  75. package/dist/ui/use-chat/useStreamingTiming.d.ts +7 -3
  76. package/dist/ui/use-chat/useStreamingTiming.d.ts.map +1 -1
  77. package/dist/ui/use-chat/useStreamingTiming.js +60 -75
  78. package/dist/ui/use-chat/useStreamingTiming.js.map +1 -1
  79. package/dist/ui/utils/convertMessage.d.ts +29 -20
  80. package/dist/ui/utils/convertMessage.d.ts.map +1 -1
  81. package/dist/ui/utils/convertMessage.js +207 -301
  82. package/dist/ui/utils/convertMessage.js.map +1 -1
  83. package/dist/ui/utils/sliceMessagesUntil.d.ts +6 -2
  84. package/dist/ui/utils/sliceMessagesUntil.d.ts.map +1 -1
  85. package/dist/ui/utils/sliceMessagesUntil.js +10 -10
  86. package/dist/ui/utils/sliceMessagesUntil.js.map +1 -1
  87. package/dist/ui/utils/toCreateMessage.d.ts +7 -3
  88. package/dist/ui/utils/toCreateMessage.d.ts.map +1 -1
  89. package/dist/ui/utils/toCreateMessage.js +34 -38
  90. package/dist/ui/utils/toCreateMessage.js.map +1 -1
  91. package/dist/ui/utils/vercelAttachmentAdapter.d.ts +6 -2
  92. package/dist/ui/utils/vercelAttachmentAdapter.d.ts.map +1 -1
  93. package/dist/ui/utils/vercelAttachmentAdapter.js +37 -35
  94. package/dist/ui/utils/vercelAttachmentAdapter.js.map +1 -1
  95. package/dist/usage.d.ts +15 -12
  96. package/dist/usage.d.ts.map +1 -1
  97. package/dist/usage.js +80 -99
  98. package/dist/usage.js.map +1 -1
  99. package/package.json +11 -11
  100. package/src/ui/use-chat/useAISDKRuntime.test.ts +2 -2
  101. package/src/ui/use-chat/useAISDKRuntime.ts +8 -0
  102. package/src/ui/utils/convertMessage.test.ts +71 -6
  103. package/src/ui/utils/convertMessage.ts +27 -25
  104. package/dist/index.d.ts.map +0 -1
  105. package/dist/index.js.map +0 -1
@@ -1,92 +1,71 @@
1
1
  "use client";
2
- import { useChat } from "@ai-sdk/react";
3
- import { useCloudThreadListAdapter, useRemoteThreadListRuntime, } from "@assistant-ui/core/react";
4
- import { useAui, useAuiState } from "@assistant-ui/store";
5
- import { useAISDKRuntime, } from "./useAISDKRuntime.js";
2
+ import { useAISDKRuntime } from "./useAISDKRuntime.js";
6
3
  import { AssistantChatTransport } from "./AssistantChatTransport.js";
7
4
  import { useEffect, useMemo, useRef } from "react";
5
+ import { useCloudThreadListAdapter, useRemoteThreadListRuntime } from "@assistant-ui/core/react";
6
+ import { useAui, useAuiState } from "@assistant-ui/store";
7
+ import { useChat } from "@ai-sdk/react";
8
+ //#region src/ui/use-chat/useChatRuntime.ts
8
9
  const useDynamicChatTransport = (transport) => {
9
- // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
10
- const transportRef = useRef(transport);
11
- // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
12
- useEffect(() => {
13
- transportRef.current = transport;
14
- });
15
- // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
16
- const dynamicTransport = useMemo(() => new Proxy(transportRef.current, {
17
- get(_, prop) {
18
- const res = transportRef.current[prop];
19
- return typeof res === "function"
20
- ? res.bind(transportRef.current)
21
- : res;
22
- },
23
- }), []);
24
- return dynamicTransport;
10
+ const transportRef = useRef(transport);
11
+ useEffect(() => {
12
+ transportRef.current = transport;
13
+ });
14
+ return useMemo(() => new Proxy(transportRef.current, { get(_, prop) {
15
+ const res = transportRef.current[prop];
16
+ return typeof res === "function" ? res.bind(transportRef.current) : res;
17
+ } }), []);
25
18
  };
26
19
  const getResumableAdapter = (transport) => {
27
- if (transport instanceof AssistantChatTransport) {
28
- return transport.getResumableAdapter();
29
- }
30
- const candidate = transport
31
- .getResumableAdapter;
32
- if (typeof candidate !== "function")
33
- return undefined;
34
- return candidate.call(transport);
20
+ if (transport instanceof AssistantChatTransport) return transport.getResumableAdapter();
21
+ const candidate = transport.getResumableAdapter;
22
+ if (typeof candidate !== "function") return void 0;
23
+ return candidate.call(transport);
35
24
  };
36
25
  const useChatThreadRuntime = (options) => {
37
- const { adapters, transport: transportOptions, toCreateMessage, onResume, suggestions, ...chatOptions } = options ?? {};
38
- // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
39
- const transport = useDynamicChatTransport(transportOptions ?? new AssistantChatTransport());
40
- // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
41
- const id = useAuiState((s) => s.threadListItem.id);
42
- // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
43
- const aui = useAui();
44
- // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
45
- const chat = useChat({
46
- ...chatOptions,
47
- id,
48
- transport,
49
- });
50
- // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
51
- const runtime = useAISDKRuntime(chat, {
52
- adapters,
53
- ...(toCreateMessage && { toCreateMessage }),
54
- ...(onResume && { onResume }),
55
- ...(suggestions && { suggestions }),
56
- });
57
- if (transport instanceof AssistantChatTransport) {
58
- transport.setRuntime(runtime);
59
- transport.__internal_setGetThreadListItem(() => aui.threadListItem.source ? aui.threadListItem() : undefined);
60
- }
61
- // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
62
- const resumeFiredRef = useRef(false);
63
- // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
64
- useEffect(() => {
65
- if (resumeFiredRef.current)
66
- return;
67
- const adapter = getResumableAdapter(transport);
68
- if (!adapter)
69
- return;
70
- const pending = adapter.storage.getStreamId();
71
- if (!pending)
72
- return;
73
- resumeFiredRef.current = true;
74
- chat.resumeStream().catch((err) => {
75
- console.warn("[assistant-ui] resumable: resume failed; clearing stored stream id", err);
76
- adapter.storage.clear();
77
- });
78
- }, [transport, chat]);
79
- return runtime;
26
+ const { adapters, transport: transportOptions, toCreateMessage, onResume, suggestions, ...chatOptions } = options ?? {};
27
+ const transport = useDynamicChatTransport(transportOptions ?? new AssistantChatTransport());
28
+ const id = useAuiState((s) => s.threadListItem.id);
29
+ const aui = useAui();
30
+ const chat = useChat({
31
+ ...chatOptions,
32
+ id,
33
+ transport
34
+ });
35
+ const runtime = useAISDKRuntime(chat, {
36
+ adapters,
37
+ ...toCreateMessage && { toCreateMessage },
38
+ ...onResume && { onResume },
39
+ ...suggestions && { suggestions }
40
+ });
41
+ if (transport instanceof AssistantChatTransport) {
42
+ transport.setRuntime(runtime);
43
+ transport.__internal_setGetThreadListItem(() => aui.threadListItem.source ? aui.threadListItem() : void 0);
44
+ }
45
+ const resumeFiredRef = useRef(false);
46
+ useEffect(() => {
47
+ if (resumeFiredRef.current) return;
48
+ const adapter = getResumableAdapter(transport);
49
+ if (!adapter) return;
50
+ if (!adapter.storage.getStreamId()) return;
51
+ resumeFiredRef.current = true;
52
+ chat.resumeStream().catch((err) => {
53
+ console.warn("[assistant-ui] resumable: resume failed; clearing stored stream id", err);
54
+ adapter.storage.clear();
55
+ });
56
+ }, [transport, chat]);
57
+ return runtime;
80
58
  };
81
- export const useChatRuntime = ({ cloud, ...options } = {}) => {
82
- const cloudAdapter = useCloudThreadListAdapter({ cloud });
83
- return useRemoteThreadListRuntime({
84
- runtimeHook: function RuntimeHook() {
85
- // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage
86
- return useChatThreadRuntime(options);
87
- },
88
- adapter: cloudAdapter,
89
- allowNesting: true,
90
- });
59
+ const useChatRuntime = ({ cloud, ...options } = {}) => {
60
+ return useRemoteThreadListRuntime({
61
+ runtimeHook: function RuntimeHook() {
62
+ return useChatThreadRuntime(options);
63
+ },
64
+ adapter: useCloudThreadListAdapter({ cloud }),
65
+ allowNesting: true
66
+ });
91
67
  };
68
+ //#endregion
69
+ export { useChatRuntime };
70
+
92
71
  //# sourceMappingURL=useChatRuntime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useChatRuntime.js","sourceRoot":"","sources":["../../../src/ui/use-chat/useChatRuntime.ts"],"names":[],"mappings":"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"}
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 type { AssistantRuntime } 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 cloud?: AssistantCloud | undefined;\n adapters?: AISDKRuntimeAdapter[\"adapters\"] | undefined;\n toCreateMessage?: CustomToCreateMessageFunction;\n onResume?: AISDKRuntimeAdapter[\"onResume\"];\n suggestions?: AISDKRuntimeAdapter[\"suggestions\"];\n };\n\nconst useDynamicChatTransport = <UI_MESSAGE extends UIMessage = UIMessage>(\n transport: ChatTransport<UI_MESSAGE>,\n): ChatTransport<UI_MESSAGE> => {\n // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage\n const transportRef = useRef<ChatTransport<UI_MESSAGE>>(transport);\n // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage\n useEffect(() => {\n transportRef.current = transport;\n });\n // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage\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 onResume,\n suggestions,\n ...chatOptions\n } = options ?? {};\n\n // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage\n const transport = useDynamicChatTransport(\n transportOptions ?? new AssistantChatTransport(),\n );\n\n // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage\n const id = useAuiState((s) => s.threadListItem.id);\n // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage\n const aui = useAui();\n // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage\n const chat = useChat({\n ...chatOptions,\n id,\n transport,\n });\n\n // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage\n const runtime = useAISDKRuntime(chat, {\n adapters,\n ...(toCreateMessage && { toCreateMessage }),\n ...(onResume && { onResume }),\n ...(suggestions && { suggestions }),\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 // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage\n const resumeFiredRef = useRef(false);\n // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage\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 // biome-ignore lint/correctness/useHookAtTopLevel: intentional conditional/nested hook usage\n return useChatThreadRuntime(options);\n },\n adapter: cloudAdapter,\n allowNesting: true,\n });\n};\n"],"mappings":";;;;;;;;AA6BA,MAAM,2BACJ,cAC8B;CAE9B,MAAM,eAAe,OAAkC,SAAS;CAEhE,gBAAgB;EACd,aAAa,UAAU;CACzB,CAAC;CAeD,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,UACA,aACA,GAAG,gBACD,WAAW,CAAC;CAGhB,MAAM,YAAY,wBAChB,oBAAoB,IAAI,uBAAuB,CACjD;CAGA,MAAM,KAAK,aAAa,MAAM,EAAE,eAAe,EAAE;CAEjD,MAAM,MAAM,OAAO;CAEnB,MAAM,OAAO,QAAQ;EACnB,GAAG;EACH;EACA;CACF,CAAC;CAGD,MAAM,UAAU,gBAAgB,MAAM;EACpC;EACA,GAAI,mBAAmB,EAAE,gBAAgB;EACzC,GAAI,YAAY,EAAE,SAAS;EAC3B,GAAI,eAAe,EAAE,YAAY;CACnC,CAAC;CAED,IAAI,qBAAqB,wBAAwB;EAC/C,UAAU,WAAW,OAAO;EAC5B,UAAU,sCACR,IAAI,eAAe,SAAS,IAAI,eAAe,IAAI,KAAA,CACrD;CACF;CAGA,MAAM,iBAAiB,OAAO,KAAK;CAEnC,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,EAAE,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;GAElC,OAAO,qBAAqB,OAAO;EACrC;EACA,SANmB,0BAA0B,EAAE,MAAM,CAMjC;EACpB,cAAc;CAChB,CAAC;AACH"}
@@ -1,5 +1,9 @@
1
- import type { AssistantRuntime, ThreadHistoryAdapter, ThreadMessage, MessageFormatAdapter, MessageFormatRepository, ExportedMessageRepository } from "@assistant-ui/core";
2
- import { type RefObject } from "react";
3
- export declare const toExportedMessageRepository: <TMessage>(toThreadMessages: (messages: TMessage[]) => ThreadMessage[], messages: MessageFormatRepository<TMessage>) => ExportedMessageRepository;
4
- export declare const useExternalHistory: <TMessage>(runtimeRef: RefObject<AssistantRuntime>, historyAdapter: ThreadHistoryAdapter | undefined, toThreadMessages: (messages: TMessage[]) => ThreadMessage[], storageFormatAdapter: MessageFormatAdapter<TMessage, any>, onSetMessages: (messages: TMessage[]) => void) => boolean;
1
+ import { RefObject } from "react";
2
+ import { AssistantRuntime, ExportedMessageRepository, MessageFormatAdapter, MessageFormatRepository, ThreadHistoryAdapter, ThreadMessage } from "@assistant-ui/core";
3
+
4
+ //#region src/ui/use-chat/useExternalHistory.d.ts
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) => boolean;
7
+ //#endregion
8
+ export { toExportedMessageRepository, useExternalHistory };
5
9
  //# sourceMappingURL=useExternalHistory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useExternalHistory.d.ts","sourceRoot":"","sources":["../../../src/ui/use-chat/useExternalHistory.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,gBAAgB,EAChB,oBAAoB,EACpB,aAAa,EACb,oBAAoB,EACpB,uBAAuB,EACvB,yBAAyB,EAC1B,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAIL,KAAK,SAAS,EAGf,MAAM,OAAO,CAAC;AAEf,eAAO,MAAM,2BAA2B,GAAI,QAAQ,EAClD,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,EAC3D,UAAU,uBAAuB,CAAC,QAAQ,CAAC,KAC1C,yBAWF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAAI,QAAQ,EACzC,YAAY,SAAS,CAAC,gBAAgB,CAAC,EACvC,gBAAgB,oBAAoB,GAAG,SAAS,EAChD,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,aAAa,EAAE,EAC3D,sBAAsB,oBAAoB,CAAC,QAAQ,EAAE,GAAG,CAAC,EACzD,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,IAAI,YAmP9C,CAAC"}
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,cAaU,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,207 +1,185 @@
1
1
  "use client";
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
2
3
  import { getExternalStoreMessages } from "@assistant-ui/core";
3
4
  import { MessageRepository } from "@assistant-ui/core/internal";
4
5
  import { useAui } from "@assistant-ui/store";
5
- import { useRef, useEffect, useState, useCallback, useMemo, } from "react";
6
- export const toExportedMessageRepository = (toThreadMessages, messages) => {
7
- return {
8
- headId: messages.headId,
9
- messages: messages.messages.map((m) => {
10
- const message = toThreadMessages([m.message])[0];
11
- return {
12
- ...m,
13
- message,
14
- };
15
- }),
16
- };
6
+ //#region src/ui/use-chat/useExternalHistory.ts
7
+ const toExportedMessageRepository = (toThreadMessages, messages) => {
8
+ return {
9
+ headId: messages.headId,
10
+ messages: messages.messages.map((m) => {
11
+ const message = toThreadMessages([m.message])[0];
12
+ return {
13
+ ...m,
14
+ message
15
+ };
16
+ })
17
+ };
17
18
  };
18
- export const useExternalHistory = (runtimeRef, historyAdapter, toThreadMessages, storageFormatAdapter, onSetMessages) => {
19
- const loadedRef = useRef(false);
20
- const aui = useAui();
21
- const optionalThreadListItem = useCallback(() => (aui.threadListItem.source ? aui.threadListItem() : null), [aui]);
22
- const [isLoading, setIsLoading] = useState(false);
23
- const historyIds = useRef(new Set());
24
- const onSetMessagesRef = useRef(onSetMessages);
25
- useEffect(() => {
26
- onSetMessagesRef.current = onSetMessages;
27
- });
28
- const formatAdapter = useMemo(() => {
29
- if (!historyAdapter)
30
- return undefined;
31
- if (!historyAdapter.withFormat) {
32
- throw new Error("useAISDKRuntime: ThreadHistoryAdapter is missing the required `withFormat` method.");
33
- }
34
- return historyAdapter.withFormat(storageFormatAdapter);
35
- }, [historyAdapter, storageFormatAdapter]);
36
- useEffect(() => {
37
- if (!formatAdapter || loadedRef.current)
38
- return;
39
- const loadHistory = async () => {
40
- setIsLoading(true);
41
- try {
42
- const repo = await formatAdapter.load();
43
- if (repo && repo.messages.length > 0) {
44
- const converted = toExportedMessageRepository(toThreadMessages, repo);
45
- runtimeRef.current.thread.import(converted);
46
- const tempRepo = new MessageRepository();
47
- tempRepo.import(converted);
48
- const messages = tempRepo.getMessages();
49
- onSetMessagesRef.current(messages.flatMap((getExternalStoreMessages)));
50
- historyIds.current = new Set(converted.messages.map((m) => m.message.id));
51
- }
52
- }
53
- catch (error) {
54
- console.error("Failed to load message history:", error);
55
- }
56
- finally {
57
- setIsLoading(false);
58
- }
59
- };
60
- loadedRef.current = true;
61
- if (!optionalThreadListItem()?.getState().remoteId) {
62
- setIsLoading(false);
63
- return;
64
- }
65
- loadHistory();
66
- }, [formatAdapter, toThreadMessages, runtimeRef, optionalThreadListItem]);
67
- const runStartRef = useRef(null);
68
- const persistTimerRef = useRef(null);
69
- const stepBoundariesRef = useRef([]);
70
- const wasRunningRef = useRef(false);
71
- const toolCallCountRef = useRef(0);
72
- useEffect(() => {
73
- if (!formatAdapter)
74
- return;
75
- const unsubscribe = runtimeRef.current.thread.subscribe(() => {
76
- const { isRunning } = runtimeRef.current.thread.getState();
77
- const wasRunning = wasRunningRef.current;
78
- wasRunningRef.current = isRunning;
79
- // Track step boundaries by content changes (more reliable than isRunning)
80
- if (runStartRef.current != null) {
81
- const lastMsg = runtimeRef.current.thread.getState().messages.at(-1);
82
- if (lastMsg?.role === "assistant") {
83
- const currentToolCallCount = lastMsg.content.filter((p) => p.type === "tool-call").length;
84
- while (toolCallCountRef.current < currentToolCallCount) {
85
- stepBoundariesRef.current.push(Date.now() - runStartRef.current);
86
- toolCallCountRef.current++;
87
- }
88
- }
89
- }
90
- if (isRunning) {
91
- if (runStartRef.current == null) {
92
- runStartRef.current = Date.now();
93
- stepBoundariesRef.current = [];
94
- toolCallCountRef.current = 0;
95
- }
96
- // Cancel any pending persist — isRunning went back to true
97
- if (persistTimerRef.current) {
98
- clearTimeout(persistTimerRef.current);
99
- persistTimerRef.current = null;
100
- }
101
- return;
102
- }
103
- // Only act on the true→false transition
104
- if (!wasRunning)
105
- return;
106
- // Record step boundary offset (synchronous for accuracy)
107
- if (runStartRef.current != null) {
108
- stepBoundariesRef.current.push(Date.now() - runStartRef.current);
109
- }
110
- // Debounce: wait one macrotask so agentic step flickers are absorbed
111
- if (persistTimerRef.current)
112
- clearTimeout(persistTimerRef.current);
113
- persistTimerRef.current = setTimeout(async () => {
114
- persistTimerRef.current = null;
115
- // Re-read latest state — may have changed since the timeout was scheduled
116
- const latest = runtimeRef.current.thread.getState();
117
- if (latest.isRunning)
118
- return; // was just a flicker
119
- // Derive durationMs from the last boundary (covers all steps)
120
- const boundaries = stepBoundariesRef.current;
121
- const durationMs = boundaries.length > 0 ? boundaries.at(-1) : undefined;
122
- // Fallback: if only 1 boundary but message has multiple steps, distribute evenly
123
- if (boundaries.length === 1 && durationMs != null) {
124
- const lastAssistant = latest.messages.findLast((m) => m.role === "assistant");
125
- if (lastAssistant) {
126
- const tcCount = lastAssistant.content.filter((p) => p.type === "tool-call").length;
127
- if (tcCount > 0) {
128
- const totalSteps = tcCount + 1;
129
- const stepDur = durationMs / totalSteps;
130
- boundaries.length = 0;
131
- for (let i = 0; i < totalSteps; i++) {
132
- boundaries.push(Math.round((i + 1) * stepDur));
133
- }
134
- }
135
- }
136
- }
137
- // Build per-step timestamps when there are multiple steps
138
- const stepTimestamps = boundaries.length > 1
139
- ? boundaries.map((endMs, i) => ({
140
- start_ms: i === 0 ? 0 : boundaries[i - 1],
141
- end_ms: endMs,
142
- }))
143
- : undefined;
144
- runStartRef.current = null;
145
- stepBoundariesRef.current = [];
146
- const telemetryOptions = {
147
- ...(durationMs != null ? { durationMs } : undefined),
148
- ...(stepTimestamps != null ? { stepTimestamps } : undefined),
149
- };
150
- const { messages } = latest;
151
- let lastInnerMessageId = null;
152
- const getLastInnerId = (msgs) => msgs.length > 0 ? storageFormatAdapter.getId(msgs.at(-1)) : null;
153
- const toBatchItems = (msgs) => msgs.map((msg, idx) => ({
154
- parentId: idx === 0
155
- ? lastInnerMessageId
156
- : storageFormatAdapter.getId(msgs[idx - 1]),
157
- message: msg,
158
- }));
159
- for (const message of messages) {
160
- const innerMessages = getExternalStoreMessages(message);
161
- const isReady = message.status === undefined ||
162
- message.status.type === "complete" ||
163
- message.status.type === "incomplete";
164
- if (!isReady) {
165
- lastInnerMessageId =
166
- getLastInnerId(innerMessages) ?? lastInnerMessageId;
167
- continue;
168
- }
169
- if (historyIds.current.has(message.id)) {
170
- if (durationMs !== undefined) {
171
- let parentId = lastInnerMessageId;
172
- for (const innerMessage of innerMessages) {
173
- try {
174
- await formatAdapter.update?.({ parentId, message: innerMessage }, storageFormatAdapter.getId(innerMessage));
175
- }
176
- catch {
177
- // ignore update failures to avoid breaking the message processing loop
178
- }
179
- parentId = storageFormatAdapter.getId(innerMessage);
180
- }
181
- }
182
- lastInnerMessageId =
183
- getLastInnerId(innerMessages) ?? lastInnerMessageId;
184
- continue;
185
- }
186
- historyIds.current.add(message.id);
187
- const batchItems = toBatchItems(innerMessages);
188
- for (const item of batchItems) {
189
- await formatAdapter.append(item);
190
- }
191
- lastInnerMessageId =
192
- getLastInnerId(innerMessages) ?? lastInnerMessageId;
193
- formatAdapter.reportTelemetry?.(batchItems, telemetryOptions);
194
- }
195
- }, 0);
196
- });
197
- return () => {
198
- unsubscribe();
199
- if (persistTimerRef.current) {
200
- clearTimeout(persistTimerRef.current);
201
- persistTimerRef.current = null;
202
- }
203
- };
204
- }, [formatAdapter, storageFormatAdapter, runtimeRef]);
205
- return isLoading;
19
+ const useExternalHistory = (runtimeRef, historyAdapter, toThreadMessages, storageFormatAdapter, onSetMessages) => {
20
+ const loadedRef = useRef(false);
21
+ const aui = useAui();
22
+ const optionalThreadListItem = useCallback(() => aui.threadListItem.source ? aui.threadListItem() : null, [aui]);
23
+ const [isLoading, setIsLoading] = useState(false);
24
+ const historyIds = useRef(/* @__PURE__ */ new Set());
25
+ const onSetMessagesRef = useRef(onSetMessages);
26
+ useEffect(() => {
27
+ onSetMessagesRef.current = onSetMessages;
28
+ });
29
+ const formatAdapter = useMemo(() => {
30
+ if (!historyAdapter) return void 0;
31
+ if (!historyAdapter.withFormat) throw new Error("useAISDKRuntime: ThreadHistoryAdapter is missing the required `withFormat` method.");
32
+ return historyAdapter.withFormat(storageFormatAdapter);
33
+ }, [historyAdapter, storageFormatAdapter]);
34
+ useEffect(() => {
35
+ if (!formatAdapter || loadedRef.current) return;
36
+ const loadHistory = async () => {
37
+ setIsLoading(true);
38
+ try {
39
+ const repo = await formatAdapter.load();
40
+ if (repo && repo.messages.length > 0) {
41
+ const converted = toExportedMessageRepository(toThreadMessages, repo);
42
+ runtimeRef.current.thread.import(converted);
43
+ const tempRepo = new MessageRepository();
44
+ tempRepo.import(converted);
45
+ const messages = tempRepo.getMessages();
46
+ onSetMessagesRef.current(messages.flatMap(getExternalStoreMessages));
47
+ historyIds.current = new Set(converted.messages.map((m) => m.message.id));
48
+ }
49
+ } catch (error) {
50
+ console.error("Failed to load message history:", error);
51
+ } finally {
52
+ setIsLoading(false);
53
+ }
54
+ };
55
+ loadedRef.current = true;
56
+ if (!optionalThreadListItem()?.getState().remoteId) {
57
+ setIsLoading(false);
58
+ return;
59
+ }
60
+ loadHistory();
61
+ }, [
62
+ formatAdapter,
63
+ toThreadMessages,
64
+ runtimeRef,
65
+ optionalThreadListItem
66
+ ]);
67
+ const runStartRef = useRef(null);
68
+ const persistTimerRef = useRef(null);
69
+ const stepBoundariesRef = useRef([]);
70
+ const wasRunningRef = useRef(false);
71
+ const toolCallCountRef = useRef(0);
72
+ useEffect(() => {
73
+ if (!formatAdapter) return;
74
+ const unsubscribe = runtimeRef.current.thread.subscribe(() => {
75
+ const { isRunning } = runtimeRef.current.thread.getState();
76
+ const wasRunning = wasRunningRef.current;
77
+ wasRunningRef.current = isRunning;
78
+ if (runStartRef.current != null) {
79
+ const lastMsg = runtimeRef.current.thread.getState().messages.at(-1);
80
+ if (lastMsg?.role === "assistant") {
81
+ const currentToolCallCount = lastMsg.content.filter((p) => p.type === "tool-call").length;
82
+ while (toolCallCountRef.current < currentToolCallCount) {
83
+ stepBoundariesRef.current.push(Date.now() - runStartRef.current);
84
+ toolCallCountRef.current++;
85
+ }
86
+ }
87
+ }
88
+ if (isRunning) {
89
+ if (runStartRef.current == null) {
90
+ runStartRef.current = Date.now();
91
+ stepBoundariesRef.current = [];
92
+ toolCallCountRef.current = 0;
93
+ }
94
+ if (persistTimerRef.current) {
95
+ clearTimeout(persistTimerRef.current);
96
+ persistTimerRef.current = null;
97
+ }
98
+ return;
99
+ }
100
+ if (!wasRunning) return;
101
+ if (runStartRef.current != null) stepBoundariesRef.current.push(Date.now() - runStartRef.current);
102
+ if (persistTimerRef.current) clearTimeout(persistTimerRef.current);
103
+ persistTimerRef.current = setTimeout(async () => {
104
+ persistTimerRef.current = null;
105
+ const latest = runtimeRef.current.thread.getState();
106
+ if (latest.isRunning) return;
107
+ const boundaries = stepBoundariesRef.current;
108
+ const durationMs = boundaries.length > 0 ? boundaries.at(-1) : void 0;
109
+ if (boundaries.length === 1 && durationMs != null) {
110
+ const lastAssistant = latest.messages.findLast((m) => m.role === "assistant");
111
+ if (lastAssistant) {
112
+ const tcCount = lastAssistant.content.filter((p) => p.type === "tool-call").length;
113
+ if (tcCount > 0) {
114
+ const totalSteps = tcCount + 1;
115
+ const stepDur = durationMs / totalSteps;
116
+ boundaries.length = 0;
117
+ for (let i = 0; i < totalSteps; i++) boundaries.push(Math.round((i + 1) * stepDur));
118
+ }
119
+ }
120
+ }
121
+ const stepTimestamps = boundaries.length > 1 ? boundaries.map((endMs, i) => ({
122
+ start_ms: i === 0 ? 0 : boundaries[i - 1],
123
+ end_ms: endMs
124
+ })) : void 0;
125
+ runStartRef.current = null;
126
+ stepBoundariesRef.current = [];
127
+ const telemetryOptions = {
128
+ ...durationMs != null ? { durationMs } : void 0,
129
+ ...stepTimestamps != null ? { stepTimestamps } : void 0
130
+ };
131
+ const { messages } = latest;
132
+ let lastInnerMessageId = null;
133
+ const getLastInnerId = (msgs) => msgs.length > 0 ? storageFormatAdapter.getId(msgs.at(-1)) : null;
134
+ const toBatchItems = (msgs) => msgs.map((msg, idx) => ({
135
+ parentId: idx === 0 ? lastInnerMessageId : storageFormatAdapter.getId(msgs[idx - 1]),
136
+ message: msg
137
+ }));
138
+ for (const message of messages) {
139
+ const innerMessages = getExternalStoreMessages(message);
140
+ if (!(message.status === void 0 || message.status.type === "complete" || message.status.type === "incomplete")) {
141
+ lastInnerMessageId = getLastInnerId(innerMessages) ?? lastInnerMessageId;
142
+ continue;
143
+ }
144
+ if (historyIds.current.has(message.id)) {
145
+ if (durationMs !== void 0) {
146
+ let parentId = lastInnerMessageId;
147
+ for (const innerMessage of innerMessages) {
148
+ try {
149
+ await formatAdapter.update?.({
150
+ parentId,
151
+ message: innerMessage
152
+ }, storageFormatAdapter.getId(innerMessage));
153
+ } catch {}
154
+ parentId = storageFormatAdapter.getId(innerMessage);
155
+ }
156
+ }
157
+ lastInnerMessageId = getLastInnerId(innerMessages) ?? lastInnerMessageId;
158
+ continue;
159
+ }
160
+ historyIds.current.add(message.id);
161
+ const batchItems = toBatchItems(innerMessages);
162
+ for (const item of batchItems) await formatAdapter.append(item);
163
+ lastInnerMessageId = getLastInnerId(innerMessages) ?? lastInnerMessageId;
164
+ formatAdapter.reportTelemetry?.(batchItems, telemetryOptions);
165
+ }
166
+ }, 0);
167
+ });
168
+ return () => {
169
+ unsubscribe();
170
+ if (persistTimerRef.current) {
171
+ clearTimeout(persistTimerRef.current);
172
+ persistTimerRef.current = null;
173
+ }
174
+ };
175
+ }, [
176
+ formatAdapter,
177
+ storageFormatAdapter,
178
+ runtimeRef
179
+ ]);
180
+ return isLoading;
206
181
  };
182
+ //#endregion
183
+ export { toExportedMessageRepository, useExternalHistory };
184
+
207
185
  //# sourceMappingURL=useExternalHistory.js.map