@paymanai/payman-typescript-ask-sdk 1.2.4 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { useState, useRef, useMemo, useCallback, useEffect } from 'react';
1
+ import { useState, useRef, useCallback, useMemo, useEffect } from 'react';
2
2
 
3
3
  // src/hooks/useChat.ts
4
4
 
@@ -160,6 +160,8 @@ function getEventMessage(event) {
160
160
  return event.workerName ? `${event.workerName} thinking...` : "Thinking...";
161
161
  case "INTENT_THINKING_CONT":
162
162
  return event.message || "";
163
+ case "KEEP_ALIVE":
164
+ return "";
163
165
  default:
164
166
  return eventType;
165
167
  }
@@ -196,6 +198,9 @@ function completeLastInProgressStep(steps) {
196
198
  }
197
199
  function processStreamEvent(event, state) {
198
200
  const eventType = event.eventType;
201
+ if (typeof eventType === "string" && eventType.toUpperCase() === "KEEP_ALIVE") {
202
+ return state;
203
+ }
199
204
  const message = getEventMessage(event);
200
205
  if (eventType !== "INTENT_THINKING" && eventType !== "INTENT_THINKING_CONT") {
201
206
  if (state.currentThinkingStepId) {
@@ -612,6 +617,84 @@ async function cancelUserAction(config, userActionId) {
612
617
  async function resendUserAction(config, userActionId) {
613
618
  return sendUserActionRequest(config, userActionId, "resend");
614
619
  }
620
+
621
+ // src/utils/chatStore.ts
622
+ var memoryStore = /* @__PURE__ */ new Map();
623
+ var chatStore = {
624
+ get(key) {
625
+ return memoryStore.get(key) ?? [];
626
+ },
627
+ set(key, messages) {
628
+ memoryStore.set(key, messages);
629
+ },
630
+ delete(key) {
631
+ memoryStore.delete(key);
632
+ }
633
+ };
634
+
635
+ // src/utils/activeStreamStore.ts
636
+ var streams = /* @__PURE__ */ new Map();
637
+ var activeStreamStore = {
638
+ has(key) {
639
+ return streams.has(key);
640
+ },
641
+ get(key) {
642
+ const entry = streams.get(key);
643
+ if (!entry) return null;
644
+ return { messages: entry.messages, isWaiting: entry.isWaiting };
645
+ },
646
+ // Called before startStream — registers the controller and initial messages
647
+ start(key, abortController, initialMessages) {
648
+ const existing = streams.get(key);
649
+ streams.set(key, {
650
+ messages: initialMessages,
651
+ isWaiting: true,
652
+ abortController,
653
+ listeners: existing?.listeners ?? /* @__PURE__ */ new Set()
654
+ });
655
+ },
656
+ // Called by the stream on every event — applies the same updater pattern React uses
657
+ applyMessages(key, updater) {
658
+ const entry = streams.get(key);
659
+ if (!entry) return;
660
+ const next = typeof updater === "function" ? updater(entry.messages) : updater;
661
+ entry.messages = next;
662
+ entry.listeners.forEach((l) => l(next, entry.isWaiting));
663
+ },
664
+ setWaiting(key, waiting) {
665
+ const entry = streams.get(key);
666
+ if (!entry) return;
667
+ entry.isWaiting = waiting;
668
+ entry.listeners.forEach((l) => l(entry.messages, waiting));
669
+ },
670
+ // Called when stream completes — persists to chatStore and cleans up
671
+ complete(key) {
672
+ const entry = streams.get(key);
673
+ if (!entry) return;
674
+ entry.isWaiting = false;
675
+ entry.listeners.forEach((l) => l(entry.messages, false));
676
+ const toSave = entry.messages.filter((m) => !m.isStreaming);
677
+ if (toSave.length > 0) chatStore.set(key, toSave);
678
+ streams.delete(key);
679
+ },
680
+ // Subscribe — returns unsubscribe fn. Component calls this on mount, cleanup on unmount.
681
+ subscribe(key, listener) {
682
+ const entry = streams.get(key);
683
+ if (!entry) return () => {
684
+ };
685
+ entry.listeners.add(listener);
686
+ return () => {
687
+ streams.get(key)?.listeners.delete(listener);
688
+ };
689
+ },
690
+ // Explicit user cancel — aborts the controller and removes the entry
691
+ abort(key) {
692
+ const entry = streams.get(key);
693
+ if (!entry) return;
694
+ entry.abortController.abort();
695
+ streams.delete(key);
696
+ }
697
+ };
615
698
  function useStreamManager(config, callbacks, setMessages, setIsWaitingForResponse) {
616
699
  const abortControllerRef = useRef(null);
617
700
  const configRef = useRef(config);
@@ -619,9 +702,9 @@ function useStreamManager(config, callbacks, setMessages, setIsWaitingForRespons
619
702
  const callbacksRef = useRef(callbacks);
620
703
  callbacksRef.current = callbacks;
621
704
  const startStream = useCallback(
622
- async (userMessage, streamingId, sessionId) => {
705
+ async (userMessage, streamingId, sessionId, externalAbortController) => {
623
706
  abortControllerRef.current?.abort();
624
- const abortController = new AbortController();
707
+ const abortController = externalAbortController ?? new AbortController();
625
708
  abortControllerRef.current = abortController;
626
709
  const state = {
627
710
  accumulatedContent: "",
@@ -700,6 +783,11 @@ function useStreamManager(config, callbacks, setMessages, setIsWaitingForRespons
700
783
  if (abortController.signal.aborted) {
701
784
  return;
702
785
  }
786
+ if (typeof event.eventType === "string" && event.eventType.toUpperCase() === "KEEP_ALIVE") {
787
+ if (event.executionId) state.executionId = event.executionId;
788
+ if (event.sessionId) state.currentSessionId = event.sessionId;
789
+ return;
790
+ }
703
791
  if (event.executionId) state.executionId = event.executionId;
704
792
  if (event.sessionId) state.currentSessionId = event.sessionId;
705
793
  const activeThinkingLengthBeforeProcess = state.activeThinkingText?.length ?? 0;
@@ -825,13 +913,43 @@ function useStreamManager(config, callbacks, setMessages, setIsWaitingForRespons
825
913
 
826
914
  // src/hooks/useChat.ts
827
915
  function useChat(config, callbacks = {}) {
828
- const [messages, setMessages] = useState([]);
916
+ const [messages, setMessages] = useState(() => {
917
+ if (config.userId) return chatStore.get(config.userId);
918
+ return config.initialMessages ?? [];
919
+ });
829
920
  const [isWaitingForResponse, setIsWaitingForResponse] = useState(false);
830
- const sessionIdRef = useRef(void 0);
921
+ const sessionIdRef = useRef(
922
+ config.userId ? chatStore.get(config.userId).find((m) => m.sessionId)?.sessionId ?? config.initialSessionId ?? void 0 : config.initialSessionId ?? void 0
923
+ );
924
+ const prevUserIdRef = useRef(config.userId);
831
925
  const callbacksRef = useRef(callbacks);
832
926
  callbacksRef.current = callbacks;
833
927
  const configRef = useRef(config);
834
928
  configRef.current = config;
929
+ const messagesRef = useRef(messages);
930
+ messagesRef.current = messages;
931
+ const storeAwareSetMessages = useCallback(
932
+ (updater) => {
933
+ const { userId } = configRef.current;
934
+ if (userId && activeStreamStore.has(userId)) {
935
+ activeStreamStore.applyMessages(userId, updater);
936
+ }
937
+ setMessages(updater);
938
+ },
939
+ // eslint-disable-next-line react-hooks/exhaustive-deps
940
+ []
941
+ );
942
+ const storeAwareSetIsWaiting = useCallback(
943
+ (waiting) => {
944
+ const { userId } = configRef.current;
945
+ if (userId && activeStreamStore.has(userId)) {
946
+ activeStreamStore.setWaiting(userId, waiting);
947
+ }
948
+ setIsWaitingForResponse(waiting);
949
+ },
950
+ // eslint-disable-next-line react-hooks/exhaustive-deps
951
+ []
952
+ );
835
953
  const [userActionState, setUserActionState] = useState({
836
954
  request: null,
837
955
  result: null,
@@ -874,8 +992,8 @@ function useChat(config, callbacks = {}) {
874
992
  const { startStream, cancelStream: cancelStreamManager, abortControllerRef } = useStreamManager(
875
993
  config,
876
994
  wrappedCallbacks,
877
- setMessages,
878
- setIsWaitingForResponse
995
+ storeAwareSetMessages,
996
+ storeAwareSetIsWaiting
879
997
  );
880
998
  const sendMessage = useCallback(
881
999
  async (userMessage) => {
@@ -912,11 +1030,21 @@ function useChat(config, callbacks = {}) {
912
1030
  currentMessage: void 0
913
1031
  };
914
1032
  setMessages((prev) => [...prev, streamingMsg]);
1033
+ const abortController = new AbortController();
1034
+ const { userId } = configRef.current;
1035
+ if (userId) {
1036
+ const initialMessages = [...messagesRef.current, userMsg, streamingMsg];
1037
+ activeStreamStore.start(userId, abortController, initialMessages);
1038
+ }
915
1039
  const newSessionId = await startStream(
916
1040
  userMessage,
917
1041
  streamingId,
918
- sessionIdRef.current
1042
+ sessionIdRef.current,
1043
+ abortController
919
1044
  );
1045
+ if (userId) {
1046
+ activeStreamStore.complete(userId);
1047
+ }
920
1048
  if (newSessionId && newSessionId !== sessionIdRef.current) {
921
1049
  sessionIdRef.current = newSessionId;
922
1050
  }
@@ -924,9 +1052,18 @@ function useChat(config, callbacks = {}) {
924
1052
  [startStream]
925
1053
  );
926
1054
  const clearMessages = useCallback(() => {
1055
+ if (configRef.current.userId) {
1056
+ chatStore.delete(configRef.current.userId);
1057
+ }
927
1058
  setMessages([]);
928
1059
  }, []);
1060
+ const prependMessages = useCallback((msgs) => {
1061
+ setMessages((prev) => [...msgs, ...prev]);
1062
+ }, []);
929
1063
  const cancelStream = useCallback(() => {
1064
+ if (configRef.current.userId) {
1065
+ activeStreamStore.abort(configRef.current.userId);
1066
+ }
930
1067
  cancelStreamManager();
931
1068
  setIsWaitingForResponse(false);
932
1069
  setUserActionState((prev) => ({ ...prev, request: null, result: null }));
@@ -946,6 +1083,10 @@ function useChat(config, callbacks = {}) {
946
1083
  );
947
1084
  }, [cancelStreamManager]);
948
1085
  const resetSession = useCallback(() => {
1086
+ if (configRef.current.userId) {
1087
+ activeStreamStore.abort(configRef.current.userId);
1088
+ chatStore.delete(configRef.current.userId);
1089
+ }
949
1090
  setMessages([]);
950
1091
  sessionIdRef.current = void 0;
951
1092
  abortControllerRef.current?.abort();
@@ -1008,10 +1149,48 @@ function useChat(config, callbacks = {}) {
1008
1149
  throw error;
1009
1150
  }
1010
1151
  }, []);
1152
+ useEffect(() => {
1153
+ const { userId } = config;
1154
+ if (!userId) return;
1155
+ const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting) => {
1156
+ setMessages(msgs);
1157
+ setIsWaitingForResponse(isWaiting);
1158
+ });
1159
+ const active = activeStreamStore.get(userId);
1160
+ if (active) {
1161
+ setMessages(active.messages);
1162
+ setIsWaitingForResponse(active.isWaiting);
1163
+ }
1164
+ return unsubscribe;
1165
+ }, []);
1166
+ useEffect(() => {
1167
+ if (!config.userId) return;
1168
+ const toSave = messages.filter((m) => !m.isStreaming);
1169
+ if (toSave.length > 0) {
1170
+ chatStore.set(config.userId, toSave);
1171
+ }
1172
+ }, [messages, config.userId]);
1173
+ useEffect(() => {
1174
+ const prevUserId = prevUserIdRef.current;
1175
+ prevUserIdRef.current = config.userId;
1176
+ if (prevUserId === config.userId) return;
1177
+ if (prevUserId && !config.userId) {
1178
+ chatStore.delete(prevUserId);
1179
+ setMessages([]);
1180
+ sessionIdRef.current = void 0;
1181
+ setIsWaitingForResponse(false);
1182
+ setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
1183
+ } else if (config.userId) {
1184
+ const stored = chatStore.get(config.userId);
1185
+ setMessages(stored);
1186
+ sessionIdRef.current = stored.find((m) => m.sessionId)?.sessionId;
1187
+ }
1188
+ }, [config.userId]);
1011
1189
  return {
1012
1190
  messages,
1013
1191
  sendMessage,
1014
1192
  clearMessages,
1193
+ prependMessages,
1015
1194
  cancelStream,
1016
1195
  resetSession,
1017
1196
  getSessionId,