@flamingo-stack/openframe-frontend-core 0.0.249 → 0.0.250

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 (58) hide show
  1. package/dist/{chunk-PCXI7ZB2.js → chunk-D2BC3NZ2.js} +135 -30
  2. package/dist/chunk-D2BC3NZ2.js.map +1 -0
  3. package/dist/{chunk-5ZVPKTXM.js → chunk-DZJ53RX6.js} +2 -2
  4. package/dist/{chunk-4EED3YEI.cjs → chunk-NCXHTQH2.cjs} +663 -558
  5. package/dist/chunk-NCXHTQH2.cjs.map +1 -0
  6. package/dist/{chunk-3DZ7QYNA.cjs → chunk-PDKBCCCD.cjs} +11 -11
  7. package/dist/{chunk-3DZ7QYNA.cjs.map → chunk-PDKBCCCD.cjs.map} +1 -1
  8. package/dist/{chunk-LHZYI23D.cjs → chunk-PDYT7T6K.cjs} +32 -29
  9. package/dist/chunk-PDYT7T6K.cjs.map +1 -0
  10. package/dist/{chunk-PVAYXHYF.js → chunk-PSG7H4KG.js} +2 -2
  11. package/dist/{chunk-VAKBNCV6.js → chunk-SGEO3W3F.js} +6 -3
  12. package/dist/chunk-SGEO3W3F.js.map +1 -0
  13. package/dist/{chunk-3VTHSACO.cjs → chunk-UMH4RR2F.cjs} +25 -25
  14. package/dist/{chunk-3VTHSACO.cjs.map → chunk-UMH4RR2F.cjs.map} +1 -1
  15. package/dist/components/chat/chat-message-list.d.ts.map +1 -1
  16. package/dist/components/chat/index.cjs +12 -2
  17. package/dist/components/chat/index.cjs.map +1 -1
  18. package/dist/components/chat/index.js +11 -1
  19. package/dist/components/chat/utils/history-merge.d.ts +92 -0
  20. package/dist/components/chat/utils/history-merge.d.ts.map +1 -0
  21. package/dist/components/chat/utils/index.d.ts +1 -0
  22. package/dist/components/chat/utils/index.d.ts.map +1 -1
  23. package/dist/components/contact/index.cjs +3 -3
  24. package/dist/components/contact/index.js +2 -2
  25. package/dist/components/features/index.cjs +2 -2
  26. package/dist/components/features/index.js +1 -1
  27. package/dist/components/features/policy-configuration-panel.d.ts.map +1 -1
  28. package/dist/components/index.cjs +59 -49
  29. package/dist/components/index.cjs.map +1 -1
  30. package/dist/components/index.js +13 -3
  31. package/dist/components/index.js.map +1 -1
  32. package/dist/components/navigation/index.cjs +2 -2
  33. package/dist/components/navigation/index.js +1 -1
  34. package/dist/components/related-content/index.cjs +3 -3
  35. package/dist/components/related-content/index.js +2 -2
  36. package/dist/components/related-content/related-content-section.d.ts.map +1 -1
  37. package/dist/components/tickets/index.cjs +55 -55
  38. package/dist/components/tickets/index.js +3 -3
  39. package/dist/components/ui/index.cjs +12 -2
  40. package/dist/components/ui/index.cjs.map +1 -1
  41. package/dist/components/ui/index.js +11 -1
  42. package/dist/index.cjs +12 -2
  43. package/dist/index.cjs.map +1 -1
  44. package/dist/index.js +11 -1
  45. package/package.json +1 -1
  46. package/src/components/chat/__tests__/chat-message-list.test.tsx +92 -0
  47. package/src/components/chat/chat-message-list.tsx +74 -49
  48. package/src/components/chat/utils/__tests__/history-merge.test.ts +339 -0
  49. package/src/components/chat/utils/history-merge.ts +255 -0
  50. package/src/components/chat/utils/index.ts +12 -0
  51. package/src/components/features/policy-configuration-panel.tsx +1 -0
  52. package/src/components/related-content/related-content-section.tsx +6 -2
  53. package/dist/chunk-4EED3YEI.cjs.map +0 -1
  54. package/dist/chunk-LHZYI23D.cjs.map +0 -1
  55. package/dist/chunk-PCXI7ZB2.js.map +0 -1
  56. package/dist/chunk-VAKBNCV6.js.map +0 -1
  57. /package/dist/{chunk-5ZVPKTXM.js.map → chunk-DZJ53RX6.js.map} +0 -0
  58. /package/dist/{chunk-PVAYXHYF.js.map → chunk-PSG7H4KG.js.map} +0 -0
@@ -2924,12 +2924,15 @@ var ChatMessageList = forwardRef12(
2924
2924
  onLoadMoreRef.current = onLoadMore;
2925
2925
  const isFetchingRef = useRef3(isFetchingNextPage);
2926
2926
  isFetchingRef.current = isFetchingNextPage;
2927
+ const dialogIdRef = useRef3(dialogId);
2928
+ dialogIdRef.current = dialogId;
2927
2929
  const prevRenderRef = useRef3({ dialogId: void 0, messageCount: 0, lastMessageId: void 0 });
2928
- const prependRef = useRef3({ firstMessageId: void 0, firstMessageContent: void 0, scrollHeight: 0 });
2930
+ const loadOlderAnchorRef = useRef3(null);
2929
2931
  useEffect3(() => {
2930
2932
  if (!autoScroll) return;
2931
2933
  const dialogChanged = dialogId !== prevRenderRef.current.dialogId;
2932
2934
  const prevCount = prevRenderRef.current.messageCount;
2935
+ const prevLastId = prevRenderRef.current.lastMessageId;
2933
2936
  const newCount = messages.length;
2934
2937
  const currentLastId = messages[messages.length - 1]?.id;
2935
2938
  prevRenderRef.current = { dialogId, messageCount: newCount, lastMessageId: currentLastId };
@@ -2942,7 +2945,8 @@ var ChatMessageList = forwardRef12(
2942
2945
  return;
2943
2946
  }
2944
2947
  if (newCount > prevCount) {
2945
- const newSlice = messages.slice(prevCount);
2948
+ const prevLastIdx = prevLastId ? messages.findIndex((m) => m.id === prevLastId) : -1;
2949
+ const newSlice = prevLastIdx >= 0 ? messages.slice(prevLastIdx + 1) : messages.slice(prevCount);
2946
2950
  const hasNewUser = newSlice.some((m) => m.role === "user");
2947
2951
  if (hasNewUser) {
2948
2952
  void scrollToBottom({ animation: "instant", ignoreEscapes: true });
@@ -2966,34 +2970,17 @@ var ChatMessageList = forwardRef12(
2966
2970
  }, [autoScroll, messages, dialogId, scrollToBottom, contentRef]);
2967
2971
  useLayoutEffect2(() => {
2968
2972
  const el = scrollRef.current;
2969
- if (!el) {
2970
- prependRef.current = { firstMessageId: void 0, firstMessageContent: void 0, scrollHeight: 0 };
2973
+ const anchor = loadOlderAnchorRef.current;
2974
+ if (!el || !anchor) return;
2975
+ if (anchor.dialogId !== dialogId) {
2976
+ loadOlderAnchorRef.current = null;
2971
2977
  return;
2972
2978
  }
2973
- const currentFirstId = messages[0]?.id;
2974
- const currentFirstContent = messages[0]?.content;
2975
- const prevFirstId = prependRef.current.firstMessageId;
2976
- const prevHeight = prependRef.current.scrollHeight;
2977
- if (currentFirstId !== prevFirstId) {
2978
- if (prevFirstId && prevHeight > 0) {
2979
- const prevIdx = messages.findIndex((m) => m.id === prevFirstId);
2980
- if (prevIdx > 0) {
2981
- const addedHeight = el.scrollHeight - prevHeight;
2982
- if (addedHeight > 0) el.scrollTop += addedHeight;
2983
- }
2984
- }
2985
- prependRef.current = {
2986
- firstMessageId: currentFirstId,
2987
- firstMessageContent: currentFirstContent,
2988
- scrollHeight: el.scrollHeight
2989
- };
2990
- return;
2991
- }
2992
- prependRef.current.scrollHeight = el.scrollHeight;
2993
- if (currentFirstContent !== prependRef.current.firstMessageContent) {
2994
- prependRef.current.firstMessageContent = currentFirstContent;
2995
- }
2996
- }, [messages, scrollRef]);
2979
+ const addedHeight = el.scrollHeight - anchor.scrollHeight;
2980
+ if (addedHeight <= 0) return;
2981
+ loadOlderAnchorRef.current = null;
2982
+ el.scrollTop = anchor.scrollTop + addedHeight;
2983
+ }, [messages, dialogId, scrollRef]);
2997
2984
  const messageElsRef = useRef3(/* @__PURE__ */ new Map());
2998
2985
  const refCallbacksRef = useRef3(/* @__PURE__ */ new Map());
2999
2986
  const getRegisterMessageEl = (id) => {
@@ -3065,6 +3052,14 @@ var ChatMessageList = forwardRef12(
3065
3052
  const entry = entries[0];
3066
3053
  if (!entry) return;
3067
3054
  if (entry.isIntersecting && !isFetchingRef.current) {
3055
+ const el = scrollRef.current;
3056
+ if (el) {
3057
+ loadOlderAnchorRef.current = {
3058
+ dialogId: dialogIdRef.current,
3059
+ scrollHeight: el.scrollHeight,
3060
+ scrollTop: el.scrollTop
3061
+ };
3062
+ }
3068
3063
  onLoadMoreRef.current?.();
3069
3064
  }
3070
3065
  },
@@ -3072,7 +3067,7 @@ var ChatMessageList = forwardRef12(
3072
3067
  );
3073
3068
  observer.observe(sentinelElement);
3074
3069
  return () => observer.disconnect();
3075
- }, [hasNextPage, scrollRef]);
3070
+ }, [hasNextPage, isFetchingNextPage, scrollRef]);
3076
3071
  useImperativeHandle2(ref, () => scrollRef.current, [scrollRef]);
3077
3072
  if (isLoading) {
3078
3073
  return /* @__PURE__ */ jsx22(
@@ -20247,6 +20242,7 @@ var CategorySection = ({
20247
20242
  /* @__PURE__ */ jsx175(
20248
20243
  Button,
20249
20244
  {
20245
+ type: "button",
20250
20246
  variant: "transparent",
20251
20247
  onClick: (e) => {
20252
20248
  e.stopPropagation();
@@ -37808,6 +37804,110 @@ function extractIncompleteMessageState(lastMessage) {
37808
37804
  };
37809
37805
  }
37810
37806
 
37807
+ // src/components/chat/utils/history-merge.ts
37808
+ var SYNTHETIC_REALTIME_ID_PREFIXES = ["assistant-", "user-", "error-"];
37809
+ function isSyntheticRealtimeId(id) {
37810
+ return SYNTHETIC_REALTIME_ID_PREFIXES.some((prefix) => id.startsWith(prefix));
37811
+ }
37812
+ function flattenMessagePagesChronological(pages) {
37813
+ if (!pages) return [];
37814
+ return [...pages].reverse().flatMap((page) => [...page.messages].reverse());
37815
+ }
37816
+ function maxPersistedStreamSeq(pages) {
37817
+ let max = 0;
37818
+ if (!pages) return max;
37819
+ for (const page of pages) {
37820
+ for (const msg of page.messages) {
37821
+ const seq = msg.lastChunkStreamSeq;
37822
+ if (typeof seq === "number" && seq > max) max = seq;
37823
+ }
37824
+ }
37825
+ return max;
37826
+ }
37827
+ function mergeHistoryWithRealtime(input) {
37828
+ const {
37829
+ processedHistory,
37830
+ rawHistoryIds,
37831
+ existingMessages,
37832
+ streamingMessageId,
37833
+ historyFetchedAt,
37834
+ historyMaxStreamSeq = 0,
37835
+ realtimeSeenStreamSeq = 0
37836
+ } = input;
37837
+ if (processedHistory.length === 0) return existingMessages;
37838
+ const processedIds = new Set(processedHistory.map((m) => m.id));
37839
+ const seqCoverageKnown = realtimeSeenStreamSeq > 0 && historyMaxStreamSeq > 0;
37840
+ const historyCoversRealtime = seqCoverageKnown ? historyMaxStreamSeq >= realtimeSeenStreamSeq : null;
37841
+ const trailing = processedHistory[processedHistory.length - 1];
37842
+ const historyTrailingAssistant = trailing?.role === "assistant" ? trailing : null;
37843
+ const historyBatchId = historyTrailingAssistant && Array.isArray(historyTrailingAssistant.content) ? historyTrailingAssistant.content.find((s) => s.type === "approval_batch")?.data?.approvalRequestId ?? null : null;
37844
+ let processedToUse = processedHistory;
37845
+ const pinnedSyntheticIds = /* @__PURE__ */ new Set();
37846
+ const droppedSyntheticIds = /* @__PURE__ */ new Set();
37847
+ if (historyBatchId) {
37848
+ const batchTwins = existingMessages.filter(
37849
+ (m) => m.role === "assistant" && Array.isArray(m.content) && m.content.some(
37850
+ (s) => s.type === "approval_batch" && s.data?.approvalRequestId === historyBatchId
37851
+ )
37852
+ );
37853
+ const existingWithSameBatch = batchTwins.find((m) => m.id === streamingMessageId) ?? batchTwins[batchTwins.length - 1];
37854
+ if (existingWithSameBatch && Array.isArray(existingWithSameBatch.content)) {
37855
+ const histSize = Array.isArray(historyTrailingAssistant?.content) ? historyTrailingAssistant.content.length : 0;
37856
+ const realtimeSize = existingWithSameBatch.content.length;
37857
+ if (existingWithSameBatch.id === streamingMessageId || realtimeSize > histSize) {
37858
+ processedToUse = processedHistory.slice(0, -1);
37859
+ pinnedSyntheticIds.add(existingWithSameBatch.id);
37860
+ } else {
37861
+ droppedSyntheticIds.add(existingWithSameBatch.id);
37862
+ }
37863
+ }
37864
+ }
37865
+ const realtimeMessages = existingMessages.filter((m) => {
37866
+ if (pinnedSyntheticIds.has(m.id)) return true;
37867
+ if (droppedSyntheticIds.has(m.id)) return false;
37868
+ if (processedIds.has(m.id)) return false;
37869
+ if (rawHistoryIds?.has(m.id)) return false;
37870
+ if (m.role === "user" && m.id.startsWith("optimistic-") && typeof m.content === "string") {
37871
+ const canBeInSnapshot = (m.timestamp?.getTime() ?? 0) <= historyFetchedAt;
37872
+ return !(canBeInSnapshot && processedToUse.some((pm) => pm.role === "user" && pm.content === m.content));
37873
+ }
37874
+ if (isSyntheticRealtimeId(m.id) && m.id !== streamingMessageId) {
37875
+ const covered = historyCoversRealtime !== null ? historyCoversRealtime : (m.timestamp?.getTime() ?? 0) <= historyFetchedAt;
37876
+ if (covered) return false;
37877
+ }
37878
+ return true;
37879
+ });
37880
+ return [...processedToUse, ...realtimeMessages];
37881
+ }
37882
+ function computeHistoryPrepend(processedHistory, existingMessages) {
37883
+ const existingIds = new Set(existingMessages.map((m) => m.id));
37884
+ const newMessages = [];
37885
+ let boundaryMessageIndex = -1;
37886
+ for (let i = 0; i < processedHistory.length; i++) {
37887
+ if (existingIds.has(processedHistory[i].id)) {
37888
+ boundaryMessageIndex = i;
37889
+ break;
37890
+ }
37891
+ newMessages.push(processedHistory[i]);
37892
+ }
37893
+ let boundaryMessageId;
37894
+ let boundaryUpdates;
37895
+ if (boundaryMessageIndex >= 0) {
37896
+ const boundaryMessage = processedHistory[boundaryMessageIndex];
37897
+ const existingBoundary = existingMessages.find((m) => m.id === boundaryMessage.id);
37898
+ if (existingBoundary) {
37899
+ const existingContent = JSON.stringify(existingBoundary.content);
37900
+ const newContent = JSON.stringify(boundaryMessage.content);
37901
+ if (existingContent !== newContent) {
37902
+ boundaryMessageId = boundaryMessage.id;
37903
+ boundaryUpdates = { content: boundaryMessage.content };
37904
+ }
37905
+ }
37906
+ }
37907
+ if (newMessages.length === 0 && !boundaryUpdates) return null;
37908
+ return { newMessages, boundaryMessageId, boundaryUpdates };
37909
+ }
37910
+
37811
37911
  // src/components/chat/utils/chip-action-class.ts
37812
37912
  var CHIP_ACTION_BUTTON_CLASS = "text-[11px] font-medium text-ods-text-secondary hover:text-ods-text-primary bg-transparent hover:bg-ods-card-hover border border-ods-border rounded-md px-2 py-1 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ods-focus";
37813
37913
 
@@ -39283,6 +39383,11 @@ export {
39283
39383
  useNatsChatAdapter,
39284
39384
  useUnifiedChat,
39285
39385
  extractIncompleteMessageState,
39386
+ SYNTHETIC_REALTIME_ID_PREFIXES,
39387
+ flattenMessagePagesChronological,
39388
+ maxPersistedStreamSeq,
39389
+ mergeHistoryWithRealtime,
39390
+ computeHistoryPrepend,
39286
39391
  CHIP_ACTION_BUTTON_CLASS,
39287
39392
  chatChipClass,
39288
39393
  clickupTaskUrl,
@@ -39610,4 +39715,4 @@ export {
39610
39715
  LogsList,
39611
39716
  assets
39612
39717
  };
39613
- //# sourceMappingURL=chunk-PCXI7ZB2.js.map
39718
+ //# sourceMappingURL=chunk-D2BC3NZ2.js.map