@helpai/elements 0.61.2 → 0.61.4

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/index.mjs CHANGED
@@ -29,7 +29,7 @@ var BRAND = {
29
29
  };
30
30
 
31
31
  // src/core/version.ts
32
- var ELEMENTS_VERSION = true ? "0.61.2" : "0.0.0-dev";
32
+ var ELEMENTS_VERSION = true ? "0.61.4" : "0.0.0-dev";
33
33
  var ELEMENTS_VERSION_PARAM = "_ev";
34
34
 
35
35
  // src/i18n/strings.ts
@@ -897,7 +897,7 @@ function resolveInitial() {
897
897
  }
898
898
  } catch {
899
899
  }
900
- if (window[GLOBAL_FLAG_KEY]) return 4;
900
+ if (Reflect.get(window, GLOBAL_FLAG_KEY)) return 4;
901
901
  return 2;
902
902
  }
903
903
  function parseToIndex(input) {
@@ -4415,8 +4415,7 @@ function createLocalVoice(locale) {
4415
4415
  };
4416
4416
  }
4417
4417
  function getSpeechRecognitionCtor() {
4418
- const g = globalThis;
4419
- return g.SpeechRecognition ?? g.webkitSpeechRecognition;
4418
+ return window.SpeechRecognition ?? window.webkitSpeechRecognition;
4420
4419
  }
4421
4420
  var CANDIDATE_MIME_TYPES = ["audio/webm;codecs=opus", "audio/webm", "audio/ogg;codecs=opus", "audio/mp4"];
4422
4421
  function createServerVoice(transcribe) {
@@ -6973,7 +6972,7 @@ function PanelContent(props2) {
6973
6972
  composerArea = null;
6974
6973
  } else if (canSend) {
6975
6974
  composerArea = /* @__PURE__ */ jsxs18(Fragment5, { children: [
6976
- /* @__PURE__ */ jsx23(Suggestions, { suggestions, onPick: onSuggestion }),
6975
+ !isStreaming && /* @__PURE__ */ jsx23(Suggestions, { suggestions, onPick: onSuggestion }),
6977
6976
  /* @__PURE__ */ jsx23(
6978
6977
  Composer,
6979
6978
  {
@@ -8240,6 +8239,7 @@ function App({ options, hostElement, bus }) {
8240
8239
  const markActiveConversationReadRef = useRef9(null);
8241
8240
  const markReadTimerRef = useRef9();
8242
8241
  useEffect16(() => () => clearTimeout(markReadTimerRef.current), []);
8242
+ const unreadIdsRef = useRef9(/* @__PURE__ */ new Set());
8243
8243
  useEffect16(() => {
8244
8244
  if (!conversationReady || homeNavSeeded.current) return;
8245
8245
  homeNavSeeded.current = true;
@@ -8439,18 +8439,11 @@ function App({ options, hostElement, bus }) {
8439
8439
  useEffect16(() => {
8440
8440
  if (effectiveLocale !== activeLocale) setActiveLocale(effectiveLocale);
8441
8441
  }, [effectiveLocale, activeLocale]);
8442
- const pendingSuggestionsRef = useRef9(null);
8443
8442
  const captureSuggestions = useCallback6((chunk) => {
8444
8443
  if (chunk.type !== "data-suggestions") return false;
8445
- pendingSuggestionsRef.current = parseSuggestions(chunk.data);
8444
+ setSuggestions(parseSuggestions(chunk.data));
8446
8445
  return true;
8447
8446
  }, []);
8448
- const flushSuggestions = useCallback6(() => {
8449
- if (pendingSuggestionsRef.current) {
8450
- setSuggestions(pendingSuggestionsRef.current);
8451
- pendingSuggestionsRef.current = null;
8452
- }
8453
- }, []);
8454
8447
  const adoptConversationRebind = useCallback6(
8455
8448
  (chunk) => {
8456
8449
  if (chunk.type !== "data-conversation-rebind") return false;
@@ -8470,7 +8463,6 @@ function App({ options, hostElement, bus }) {
8470
8463
  const runResume = useCallback6(
8471
8464
  async (handle) => {
8472
8465
  let bubble = null;
8473
- pendingSuggestionsRef.current = null;
8474
8466
  try {
8475
8467
  for await (const evt of handle.iter) {
8476
8468
  if (adoptConversationRebind(evt.chunk) || captureSuggestions(evt.chunk)) continue;
@@ -8499,7 +8491,6 @@ function App({ options, hostElement, bus }) {
8499
8491
  bubble.status = "complete";
8500
8492
  feedback.play("messageReceived");
8501
8493
  emitMessage(bus, options, "assistant", assistantText(bubble));
8502
- flushSuggestions();
8503
8494
  }
8504
8495
  }
8505
8496
  } catch (err) {
@@ -8639,7 +8630,6 @@ function App({ options, hostElement, bus }) {
8639
8630
  userPrefs: persistence.loadUserPrefs()
8640
8631
  });
8641
8632
  setStreaming(true);
8642
- pendingSuggestionsRef.current = null;
8643
8633
  const handle = transport.sendMessage(body);
8644
8634
  setActiveCancel(() => handle.cancel);
8645
8635
  setActiveDetach(() => handle.detach);
@@ -8664,7 +8654,6 @@ function App({ options, hostElement, bus }) {
8664
8654
  assistantMsg.status = "complete";
8665
8655
  feedback.play("messageReceived");
8666
8656
  emitMessage(bus, options, "assistant", assistantText(assistantMsg));
8667
- flushSuggestions();
8668
8657
  }
8669
8658
  } catch (error) {
8670
8659
  if (isAbortError(error)) {
@@ -8913,22 +8902,34 @@ function App({ options, hostElement, bus }) {
8913
8902
  bus.emit("close", void 0);
8914
8903
  options.onClose?.();
8915
8904
  }, [bus, options, persistence, panelSize, forms]);
8905
+ const recomputeUnread = useCallback6(() => {
8906
+ const onScreenConversationId = isChatActive() ? conversationIdSig.value : void 0;
8907
+ hasUnreadSig.value = [...unreadIdsRef.current].some((id) => id !== onScreenConversationId);
8908
+ }, [hasUnreadSig, conversationIdSig]);
8916
8909
  const refreshUnread = useCallback6(() => {
8917
8910
  if (!options.modules.list.some((m) => m.layout === "chat")) return;
8918
8911
  transport.listConversations({ limit: 50 }).then((res) => {
8919
- const onScreenConversationId = isChatActive() ? conversationIdSig.value : void 0;
8920
- hasUnreadSig.value = res.conversations.some((c) => c.hasUnread && c.conversationId !== onScreenConversationId);
8912
+ unreadIdsRef.current = new Set(res.conversations.filter((c) => c.hasUnread).map((c) => c.conversationId));
8913
+ recomputeUnread();
8921
8914
  }).catch((err) => log17.debug("refreshUnread failed (non-fatal)", { err }));
8922
- }, [transport, options.modules, hasUnreadSig, conversationIdSig]);
8915
+ }, [transport, options.modules, recomputeUnread]);
8916
+ const clearUnread = useCallback6(
8917
+ (conversationId) => {
8918
+ unreadIdsRef.current.delete(conversationId);
8919
+ recomputeUnread();
8920
+ },
8921
+ [recomputeUnread]
8922
+ );
8923
8923
  const markActiveConversationRead = useCallback6(() => {
8924
8924
  if (!isChatActive()) return;
8925
8925
  const conversationId = conversationIdSig.value;
8926
8926
  if (!conversationId) return;
8927
8927
  clearTimeout(markReadTimerRef.current);
8928
8928
  markReadTimerRef.current = setTimeout(() => {
8929
- void transport.markRead(conversationId).then(refreshUnread);
8929
+ clearUnread(conversationId);
8930
+ void transport.markRead(conversationId);
8930
8931
  }, MARK_READ_DELAY_MS);
8931
- }, [transport, conversationIdSig, refreshUnread]);
8932
+ }, [transport, conversationIdSig, clearUnread]);
8932
8933
  useEffect16(() => {
8933
8934
  markActiveConversationReadRef.current = markActiveConversationRead;
8934
8935
  }, [markActiveConversationRead]);
@@ -9075,7 +9076,7 @@ function App({ options, hostElement, bus }) {
9075
9076
  setView("chat");
9076
9077
  void resumeInFlight();
9077
9078
  await transport.markRead(targetConversationId);
9078
- refreshUnread();
9079
+ clearUnread(targetConversationId);
9079
9080
  } catch (err) {
9080
9081
  bus.emit("error", err);
9081
9082
  options.onError?.(err);
@@ -9088,7 +9089,7 @@ function App({ options, hostElement, bus }) {
9088
9089
  bus,
9089
9090
  options,
9090
9091
  persistence,
9091
- refreshUnread,
9092
+ clearUnread,
9092
9093
  fetchFormMarkers,
9093
9094
  withWelcomeRows,
9094
9095
  streaming,
package/package.json CHANGED
@@ -80,5 +80,5 @@
80
80
  ],
81
81
  "type": "module",
82
82
  "types": "./index.d.ts",
83
- "version": "0.61.2"
83
+ "version": "0.61.4"
84
84
  }
package/schema.mjs CHANGED
@@ -864,9 +864,7 @@ function widgetSettingsSchemaForMode(mode) {
864
864
  const ordered = [...MODE_EXTRAS[mode], ...COMMON_SECTIONS];
865
865
  const picks = {};
866
866
  for (const k of ordered) picks[k] = true;
867
- return widgetSettingsSchema.pick(
868
- picks
869
- );
867
+ return widgetSettingsSchema.pick(picks);
870
868
  }
871
869
  var ALL_MODES = ["floating", "inline", "standalone", "page", "modal", "drawer"];
872
870
 
package/web-component.mjs CHANGED
@@ -893,7 +893,7 @@ function resolveInitial() {
893
893
  }
894
894
  } catch {
895
895
  }
896
- if (window[GLOBAL_FLAG_KEY]) return 4;
896
+ if (Reflect.get(window, GLOBAL_FLAG_KEY)) return 4;
897
897
  return 2;
898
898
  }
899
899
  function parseToIndex(input) {
@@ -1930,7 +1930,7 @@ function createAuth(opts) {
1930
1930
  }
1931
1931
 
1932
1932
  // src/core/version.ts
1933
- var ELEMENTS_VERSION = true ? "0.61.2" : "0.0.0-dev";
1933
+ var ELEMENTS_VERSION = true ? "0.61.4" : "0.0.0-dev";
1934
1934
  var ELEMENTS_VERSION_PARAM = "_ev";
1935
1935
 
1936
1936
  // src/stream/types.ts
@@ -4374,8 +4374,7 @@ function createLocalVoice(locale) {
4374
4374
  };
4375
4375
  }
4376
4376
  function getSpeechRecognitionCtor() {
4377
- const g = globalThis;
4378
- return g.SpeechRecognition ?? g.webkitSpeechRecognition;
4377
+ return window.SpeechRecognition ?? window.webkitSpeechRecognition;
4379
4378
  }
4380
4379
  var CANDIDATE_MIME_TYPES = ["audio/webm;codecs=opus", "audio/webm", "audio/ogg;codecs=opus", "audio/mp4"];
4381
4380
  function createServerVoice(transcribe) {
@@ -6932,7 +6931,7 @@ function PanelContent(props2) {
6932
6931
  composerArea = null;
6933
6932
  } else if (canSend) {
6934
6933
  composerArea = /* @__PURE__ */ jsxs18(Fragment5, { children: [
6935
- /* @__PURE__ */ jsx23(Suggestions, { suggestions, onPick: onSuggestion }),
6934
+ !isStreaming && /* @__PURE__ */ jsx23(Suggestions, { suggestions, onPick: onSuggestion }),
6936
6935
  /* @__PURE__ */ jsx23(
6937
6936
  Composer,
6938
6937
  {
@@ -8199,6 +8198,7 @@ function App({ options, hostElement, bus }) {
8199
8198
  const markActiveConversationReadRef = useRef9(null);
8200
8199
  const markReadTimerRef = useRef9();
8201
8200
  useEffect16(() => () => clearTimeout(markReadTimerRef.current), []);
8201
+ const unreadIdsRef = useRef9(/* @__PURE__ */ new Set());
8202
8202
  useEffect16(() => {
8203
8203
  if (!conversationReady || homeNavSeeded.current) return;
8204
8204
  homeNavSeeded.current = true;
@@ -8398,18 +8398,11 @@ function App({ options, hostElement, bus }) {
8398
8398
  useEffect16(() => {
8399
8399
  if (effectiveLocale !== activeLocale) setActiveLocale(effectiveLocale);
8400
8400
  }, [effectiveLocale, activeLocale]);
8401
- const pendingSuggestionsRef = useRef9(null);
8402
8401
  const captureSuggestions = useCallback6((chunk) => {
8403
8402
  if (chunk.type !== "data-suggestions") return false;
8404
- pendingSuggestionsRef.current = parseSuggestions(chunk.data);
8403
+ setSuggestions(parseSuggestions(chunk.data));
8405
8404
  return true;
8406
8405
  }, []);
8407
- const flushSuggestions = useCallback6(() => {
8408
- if (pendingSuggestionsRef.current) {
8409
- setSuggestions(pendingSuggestionsRef.current);
8410
- pendingSuggestionsRef.current = null;
8411
- }
8412
- }, []);
8413
8406
  const adoptConversationRebind = useCallback6(
8414
8407
  (chunk) => {
8415
8408
  if (chunk.type !== "data-conversation-rebind") return false;
@@ -8429,7 +8422,6 @@ function App({ options, hostElement, bus }) {
8429
8422
  const runResume = useCallback6(
8430
8423
  async (handle) => {
8431
8424
  let bubble = null;
8432
- pendingSuggestionsRef.current = null;
8433
8425
  try {
8434
8426
  for await (const evt of handle.iter) {
8435
8427
  if (adoptConversationRebind(evt.chunk) || captureSuggestions(evt.chunk)) continue;
@@ -8458,7 +8450,6 @@ function App({ options, hostElement, bus }) {
8458
8450
  bubble.status = "complete";
8459
8451
  feedback.play("messageReceived");
8460
8452
  emitMessage(bus, options, "assistant", assistantText(bubble));
8461
- flushSuggestions();
8462
8453
  }
8463
8454
  }
8464
8455
  } catch (err) {
@@ -8598,7 +8589,6 @@ function App({ options, hostElement, bus }) {
8598
8589
  userPrefs: persistence.loadUserPrefs()
8599
8590
  });
8600
8591
  setStreaming(true);
8601
- pendingSuggestionsRef.current = null;
8602
8592
  const handle = transport.sendMessage(body);
8603
8593
  setActiveCancel(() => handle.cancel);
8604
8594
  setActiveDetach(() => handle.detach);
@@ -8623,7 +8613,6 @@ function App({ options, hostElement, bus }) {
8623
8613
  assistantMsg.status = "complete";
8624
8614
  feedback.play("messageReceived");
8625
8615
  emitMessage(bus, options, "assistant", assistantText(assistantMsg));
8626
- flushSuggestions();
8627
8616
  }
8628
8617
  } catch (error) {
8629
8618
  if (isAbortError(error)) {
@@ -8872,22 +8861,34 @@ function App({ options, hostElement, bus }) {
8872
8861
  bus.emit("close", void 0);
8873
8862
  options.onClose?.();
8874
8863
  }, [bus, options, persistence, panelSize, forms]);
8864
+ const recomputeUnread = useCallback6(() => {
8865
+ const onScreenConversationId = isChatActive() ? conversationIdSig.value : void 0;
8866
+ hasUnreadSig.value = [...unreadIdsRef.current].some((id) => id !== onScreenConversationId);
8867
+ }, [hasUnreadSig, conversationIdSig]);
8875
8868
  const refreshUnread = useCallback6(() => {
8876
8869
  if (!options.modules.list.some((m) => m.layout === "chat")) return;
8877
8870
  transport.listConversations({ limit: 50 }).then((res) => {
8878
- const onScreenConversationId = isChatActive() ? conversationIdSig.value : void 0;
8879
- hasUnreadSig.value = res.conversations.some((c) => c.hasUnread && c.conversationId !== onScreenConversationId);
8871
+ unreadIdsRef.current = new Set(res.conversations.filter((c) => c.hasUnread).map((c) => c.conversationId));
8872
+ recomputeUnread();
8880
8873
  }).catch((err) => log16.debug("refreshUnread failed (non-fatal)", { err }));
8881
- }, [transport, options.modules, hasUnreadSig, conversationIdSig]);
8874
+ }, [transport, options.modules, recomputeUnread]);
8875
+ const clearUnread = useCallback6(
8876
+ (conversationId) => {
8877
+ unreadIdsRef.current.delete(conversationId);
8878
+ recomputeUnread();
8879
+ },
8880
+ [recomputeUnread]
8881
+ );
8882
8882
  const markActiveConversationRead = useCallback6(() => {
8883
8883
  if (!isChatActive()) return;
8884
8884
  const conversationId = conversationIdSig.value;
8885
8885
  if (!conversationId) return;
8886
8886
  clearTimeout(markReadTimerRef.current);
8887
8887
  markReadTimerRef.current = setTimeout(() => {
8888
- void transport.markRead(conversationId).then(refreshUnread);
8888
+ clearUnread(conversationId);
8889
+ void transport.markRead(conversationId);
8889
8890
  }, MARK_READ_DELAY_MS);
8890
- }, [transport, conversationIdSig, refreshUnread]);
8891
+ }, [transport, conversationIdSig, clearUnread]);
8891
8892
  useEffect16(() => {
8892
8893
  markActiveConversationReadRef.current = markActiveConversationRead;
8893
8894
  }, [markActiveConversationRead]);
@@ -9034,7 +9035,7 @@ function App({ options, hostElement, bus }) {
9034
9035
  setView("chat");
9035
9036
  void resumeInFlight();
9036
9037
  await transport.markRead(targetConversationId);
9037
- refreshUnread();
9038
+ clearUnread(targetConversationId);
9038
9039
  } catch (err) {
9039
9040
  bus.emit("error", err);
9040
9041
  options.onError?.(err);
@@ -9047,7 +9048,7 @@ function App({ options, hostElement, bus }) {
9047
9048
  bus,
9048
9049
  options,
9049
9050
  persistence,
9050
- refreshUnread,
9051
+ clearUnread,
9051
9052
  fetchFormMarkers,
9052
9053
  withWelcomeRows,
9053
9054
  streaming,