@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.
@@ -1,6 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var react = require('react');
4
+ var reactNativeMmkv = require('react-native-mmkv');
4
5
  var expoSpeechRecognition = require('expo-speech-recognition');
5
6
 
6
7
  // src/hooks/useChat.ts
@@ -187,6 +188,8 @@ function getEventMessage(event) {
187
188
  return event.workerName ? `${event.workerName} thinking...` : "Thinking...";
188
189
  case "INTENT_THINKING_CONT":
189
190
  return event.message || "";
191
+ case "KEEP_ALIVE":
192
+ return "";
190
193
  default:
191
194
  return eventType;
192
195
  }
@@ -223,6 +226,9 @@ function completeLastInProgressStep(steps) {
223
226
  }
224
227
  function processStreamEvent(event, state) {
225
228
  const eventType = event.eventType;
229
+ if (typeof eventType === "string" && eventType.toUpperCase() === "KEEP_ALIVE") {
230
+ return state;
231
+ }
226
232
  const message = getEventMessage(event);
227
233
  if (eventType !== "INTENT_THINKING" && eventType !== "INTENT_THINKING_CONT") {
228
234
  if (state.currentThinkingStepId) {
@@ -639,6 +645,88 @@ async function cancelUserAction(config, userActionId) {
639
645
  async function resendUserAction(config, userActionId) {
640
646
  return sendUserActionRequest(config, userActionId, "resend");
641
647
  }
648
+ var storage = reactNativeMmkv.createMMKV({ id: "payman-chat-store" });
649
+ var chatStore = {
650
+ get(key) {
651
+ const raw = storage.getString(key);
652
+ if (!raw) return [];
653
+ try {
654
+ return JSON.parse(raw);
655
+ } catch {
656
+ return [];
657
+ }
658
+ },
659
+ set(key, messages) {
660
+ storage.set(key, JSON.stringify(messages));
661
+ },
662
+ delete(key) {
663
+ storage.delete(key);
664
+ }
665
+ };
666
+
667
+ // src/utils/activeStreamStore.ts
668
+ var streams = /* @__PURE__ */ new Map();
669
+ var activeStreamStore = {
670
+ has(key) {
671
+ return streams.has(key);
672
+ },
673
+ get(key) {
674
+ const entry = streams.get(key);
675
+ if (!entry) return null;
676
+ return { messages: entry.messages, isWaiting: entry.isWaiting };
677
+ },
678
+ // Called before startStream — registers the controller and initial messages
679
+ start(key, abortController, initialMessages) {
680
+ const existing = streams.get(key);
681
+ streams.set(key, {
682
+ messages: initialMessages,
683
+ isWaiting: true,
684
+ abortController,
685
+ listeners: existing?.listeners ?? /* @__PURE__ */ new Set()
686
+ });
687
+ },
688
+ // Called by the stream on every event — applies the same updater pattern React uses
689
+ applyMessages(key, updater) {
690
+ const entry = streams.get(key);
691
+ if (!entry) return;
692
+ const next = typeof updater === "function" ? updater(entry.messages) : updater;
693
+ entry.messages = next;
694
+ entry.listeners.forEach((l) => l(next, entry.isWaiting));
695
+ },
696
+ setWaiting(key, waiting) {
697
+ const entry = streams.get(key);
698
+ if (!entry) return;
699
+ entry.isWaiting = waiting;
700
+ entry.listeners.forEach((l) => l(entry.messages, waiting));
701
+ },
702
+ // Called when stream completes — persists to chatStore and cleans up
703
+ complete(key) {
704
+ const entry = streams.get(key);
705
+ if (!entry) return;
706
+ entry.isWaiting = false;
707
+ entry.listeners.forEach((l) => l(entry.messages, false));
708
+ const toSave = entry.messages.filter((m) => !m.isStreaming);
709
+ if (toSave.length > 0) chatStore.set(key, toSave);
710
+ streams.delete(key);
711
+ },
712
+ // Subscribe — returns unsubscribe fn. Component calls this on mount, cleanup on unmount.
713
+ subscribe(key, listener) {
714
+ const entry = streams.get(key);
715
+ if (!entry) return () => {
716
+ };
717
+ entry.listeners.add(listener);
718
+ return () => {
719
+ streams.get(key)?.listeners.delete(listener);
720
+ };
721
+ },
722
+ // Explicit user cancel — aborts the controller and removes the entry
723
+ abort(key) {
724
+ const entry = streams.get(key);
725
+ if (!entry) return;
726
+ entry.abortController.abort();
727
+ streams.delete(key);
728
+ }
729
+ };
642
730
  function useStreamManager(config, callbacks, setMessages, setIsWaitingForResponse) {
643
731
  const abortControllerRef = react.useRef(null);
644
732
  const configRef = react.useRef(config);
@@ -646,9 +734,9 @@ function useStreamManager(config, callbacks, setMessages, setIsWaitingForRespons
646
734
  const callbacksRef = react.useRef(callbacks);
647
735
  callbacksRef.current = callbacks;
648
736
  const startStream = react.useCallback(
649
- async (userMessage, streamingId, sessionId) => {
737
+ async (userMessage, streamingId, sessionId, externalAbortController) => {
650
738
  abortControllerRef.current?.abort();
651
- const abortController = new AbortController();
739
+ const abortController = externalAbortController ?? new AbortController();
652
740
  abortControllerRef.current = abortController;
653
741
  const state = {
654
742
  accumulatedContent: "",
@@ -727,6 +815,11 @@ function useStreamManager(config, callbacks, setMessages, setIsWaitingForRespons
727
815
  if (abortController.signal.aborted) {
728
816
  return;
729
817
  }
818
+ if (typeof event.eventType === "string" && event.eventType.toUpperCase() === "KEEP_ALIVE") {
819
+ if (event.executionId) state.executionId = event.executionId;
820
+ if (event.sessionId) state.currentSessionId = event.sessionId;
821
+ return;
822
+ }
730
823
  if (event.executionId) state.executionId = event.executionId;
731
824
  if (event.sessionId) state.currentSessionId = event.sessionId;
732
825
  const activeThinkingLengthBeforeProcess = state.activeThinkingText?.length ?? 0;
@@ -852,13 +945,43 @@ function useStreamManager(config, callbacks, setMessages, setIsWaitingForRespons
852
945
 
853
946
  // src/hooks/useChat.ts
854
947
  function useChat(config, callbacks = {}) {
855
- const [messages, setMessages] = react.useState([]);
948
+ const [messages, setMessages] = react.useState(() => {
949
+ if (config.userId) return chatStore.get(config.userId);
950
+ return config.initialMessages ?? [];
951
+ });
856
952
  const [isWaitingForResponse, setIsWaitingForResponse] = react.useState(false);
857
- const sessionIdRef = react.useRef(void 0);
953
+ const sessionIdRef = react.useRef(
954
+ config.userId ? chatStore.get(config.userId).find((m) => m.sessionId)?.sessionId ?? config.initialSessionId ?? void 0 : config.initialSessionId ?? void 0
955
+ );
956
+ const prevUserIdRef = react.useRef(config.userId);
858
957
  const callbacksRef = react.useRef(callbacks);
859
958
  callbacksRef.current = callbacks;
860
959
  const configRef = react.useRef(config);
861
960
  configRef.current = config;
961
+ const messagesRef = react.useRef(messages);
962
+ messagesRef.current = messages;
963
+ const storeAwareSetMessages = react.useCallback(
964
+ (updater) => {
965
+ const { userId } = configRef.current;
966
+ if (userId && activeStreamStore.has(userId)) {
967
+ activeStreamStore.applyMessages(userId, updater);
968
+ }
969
+ setMessages(updater);
970
+ },
971
+ // eslint-disable-next-line react-hooks/exhaustive-deps
972
+ []
973
+ );
974
+ const storeAwareSetIsWaiting = react.useCallback(
975
+ (waiting) => {
976
+ const { userId } = configRef.current;
977
+ if (userId && activeStreamStore.has(userId)) {
978
+ activeStreamStore.setWaiting(userId, waiting);
979
+ }
980
+ setIsWaitingForResponse(waiting);
981
+ },
982
+ // eslint-disable-next-line react-hooks/exhaustive-deps
983
+ []
984
+ );
862
985
  const [userActionState, setUserActionState] = react.useState({
863
986
  request: null,
864
987
  result: null,
@@ -901,8 +1024,8 @@ function useChat(config, callbacks = {}) {
901
1024
  const { startStream, cancelStream: cancelStreamManager, abortControllerRef } = useStreamManager(
902
1025
  config,
903
1026
  wrappedCallbacks,
904
- setMessages,
905
- setIsWaitingForResponse
1027
+ storeAwareSetMessages,
1028
+ storeAwareSetIsWaiting
906
1029
  );
907
1030
  const sendMessage = react.useCallback(
908
1031
  async (userMessage) => {
@@ -939,11 +1062,21 @@ function useChat(config, callbacks = {}) {
939
1062
  currentMessage: void 0
940
1063
  };
941
1064
  setMessages((prev) => [...prev, streamingMsg]);
1065
+ const abortController = new AbortController();
1066
+ const { userId } = configRef.current;
1067
+ if (userId) {
1068
+ const initialMessages = [...messagesRef.current, userMsg, streamingMsg];
1069
+ activeStreamStore.start(userId, abortController, initialMessages);
1070
+ }
942
1071
  const newSessionId = await startStream(
943
1072
  userMessage,
944
1073
  streamingId,
945
- sessionIdRef.current
1074
+ sessionIdRef.current,
1075
+ abortController
946
1076
  );
1077
+ if (userId) {
1078
+ activeStreamStore.complete(userId);
1079
+ }
947
1080
  if (newSessionId && newSessionId !== sessionIdRef.current) {
948
1081
  sessionIdRef.current = newSessionId;
949
1082
  }
@@ -951,9 +1084,18 @@ function useChat(config, callbacks = {}) {
951
1084
  [startStream]
952
1085
  );
953
1086
  const clearMessages = react.useCallback(() => {
1087
+ if (configRef.current.userId) {
1088
+ chatStore.delete(configRef.current.userId);
1089
+ }
954
1090
  setMessages([]);
955
1091
  }, []);
1092
+ const prependMessages = react.useCallback((msgs) => {
1093
+ setMessages((prev) => [...msgs, ...prev]);
1094
+ }, []);
956
1095
  const cancelStream = react.useCallback(() => {
1096
+ if (configRef.current.userId) {
1097
+ activeStreamStore.abort(configRef.current.userId);
1098
+ }
957
1099
  cancelStreamManager();
958
1100
  setIsWaitingForResponse(false);
959
1101
  setUserActionState((prev) => ({ ...prev, request: null, result: null }));
@@ -973,6 +1115,10 @@ function useChat(config, callbacks = {}) {
973
1115
  );
974
1116
  }, [cancelStreamManager]);
975
1117
  const resetSession = react.useCallback(() => {
1118
+ if (configRef.current.userId) {
1119
+ activeStreamStore.abort(configRef.current.userId);
1120
+ chatStore.delete(configRef.current.userId);
1121
+ }
976
1122
  setMessages([]);
977
1123
  sessionIdRef.current = void 0;
978
1124
  abortControllerRef.current?.abort();
@@ -1035,10 +1181,48 @@ function useChat(config, callbacks = {}) {
1035
1181
  throw error;
1036
1182
  }
1037
1183
  }, []);
1184
+ react.useEffect(() => {
1185
+ const { userId } = config;
1186
+ if (!userId) return;
1187
+ const unsubscribe = activeStreamStore.subscribe(userId, (msgs, isWaiting) => {
1188
+ setMessages(msgs);
1189
+ setIsWaitingForResponse(isWaiting);
1190
+ });
1191
+ const active = activeStreamStore.get(userId);
1192
+ if (active) {
1193
+ setMessages(active.messages);
1194
+ setIsWaitingForResponse(active.isWaiting);
1195
+ }
1196
+ return unsubscribe;
1197
+ }, []);
1198
+ react.useEffect(() => {
1199
+ if (!config.userId) return;
1200
+ const toSave = messages.filter((m) => !m.isStreaming);
1201
+ if (toSave.length > 0) {
1202
+ chatStore.set(config.userId, toSave);
1203
+ }
1204
+ }, [messages, config.userId]);
1205
+ react.useEffect(() => {
1206
+ const prevUserId = prevUserIdRef.current;
1207
+ prevUserIdRef.current = config.userId;
1208
+ if (prevUserId === config.userId) return;
1209
+ if (prevUserId && !config.userId) {
1210
+ chatStore.delete(prevUserId);
1211
+ setMessages([]);
1212
+ sessionIdRef.current = void 0;
1213
+ setIsWaitingForResponse(false);
1214
+ setUserActionState({ request: null, result: null, clearOtpTrigger: 0 });
1215
+ } else if (config.userId) {
1216
+ const stored = chatStore.get(config.userId);
1217
+ setMessages(stored);
1218
+ sessionIdRef.current = stored.find((m) => m.sessionId)?.sessionId;
1219
+ }
1220
+ }, [config.userId]);
1038
1221
  return {
1039
1222
  messages,
1040
1223
  sendMessage,
1041
1224
  clearMessages,
1225
+ prependMessages,
1042
1226
  cancelStream,
1043
1227
  resetSession,
1044
1228
  getSessionId,