@helpai/elements 0.61.1 → 0.61.3

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.1" : "0.0.0-dev";
32
+ var ELEMENTS_VERSION = true ? "0.61.3" : "0.0.0-dev";
33
33
  var ELEMENTS_VERSION_PARAM = "_ev";
34
34
 
35
35
  // src/i18n/strings.ts
@@ -2003,7 +2003,7 @@ async function* parseChatStream(response, signal7) {
2003
2003
  const trailing = buffer.trim();
2004
2004
  if (trailing) {
2005
2005
  const parsed = parseFrame(trailing);
2006
- if (parsed) yield parsed;
2006
+ if (parsed && parsed !== "done") yield parsed;
2007
2007
  }
2008
2008
  return;
2009
2009
  }
@@ -2013,6 +2013,7 @@ async function* parseChatStream(response, signal7) {
2013
2013
  const frame = buffer.slice(0, frameEnd);
2014
2014
  buffer = buffer.slice(frameEnd + 2);
2015
2015
  const parsed = parseFrame(frame);
2016
+ if (parsed === "done") return;
2016
2017
  if (parsed) yield parsed;
2017
2018
  }
2018
2019
  }
@@ -2035,7 +2036,8 @@ ${part}` : part;
2035
2036
  eventId = line.slice(3).trim();
2036
2037
  }
2037
2038
  }
2038
- if (!dataPayload || dataPayload === "[DONE]") return null;
2039
+ if (dataPayload === "[DONE]") return "done";
2040
+ if (!dataPayload) return null;
2039
2041
  try {
2040
2042
  const chunk = JSON.parse(dataPayload);
2041
2043
  log5.trace("chunk", { type: chunk.type, eventId });
@@ -2238,7 +2240,6 @@ function messageToWireParts(m) {
2238
2240
  var log6 = logger.scope("transport");
2239
2241
  var MAX_RESUME_ATTEMPTS = 3;
2240
2242
  var RESUME_BACKOFF_MS = 400;
2241
- var POST_FINISH_DRAIN_MS = 2e4;
2242
2243
  var CONTENT_CACHE_TTL_MS = 6e4;
2243
2244
  var CONVERSATIONS_CACHE_TTL_MS = 1e4;
2244
2245
  var MAX_REQUEST_RETRIES = 3;
@@ -2752,11 +2753,6 @@ var AgentTransport = class {
2752
2753
  */
2753
2754
  async *drain(source, seenIds, ctrl) {
2754
2755
  let terminal = false;
2755
- let watchdog;
2756
- const armWatchdog = () => {
2757
- if (watchdog) clearTimeout(watchdog);
2758
- watchdog = setTimeout(() => ctrl.abort(), POST_FINISH_DRAIN_MS);
2759
- };
2760
2756
  try {
2761
2757
  for await (const evt of source) {
2762
2758
  if (ctrl.signal.aborted) return true;
@@ -2766,14 +2762,11 @@ var AgentTransport = class {
2766
2762
  }
2767
2763
  yield evt;
2768
2764
  if (evt.chunk.type === "finish" || evt.chunk.type === "error") terminal = true;
2769
- if (terminal) armWatchdog();
2770
2765
  }
2771
2766
  } catch (err) {
2772
2767
  if (ctrl.signal.aborted) return true;
2773
2768
  if (err instanceof StreamError && err.status !== void 0) throw err;
2774
2769
  log6.debug("stream segment dropped", { err });
2775
- } finally {
2776
- if (watchdog) clearTimeout(watchdog);
2777
2770
  }
2778
2771
  return terminal;
2779
2772
  }
@@ -6980,7 +6973,7 @@ function PanelContent(props2) {
6980
6973
  composerArea = null;
6981
6974
  } else if (canSend) {
6982
6975
  composerArea = /* @__PURE__ */ jsxs18(Fragment5, { children: [
6983
- /* @__PURE__ */ jsx23(Suggestions, { suggestions, onPick: onSuggestion }),
6976
+ !isStreaming && /* @__PURE__ */ jsx23(Suggestions, { suggestions, onPick: onSuggestion }),
6984
6977
  /* @__PURE__ */ jsx23(
6985
6978
  Composer,
6986
6979
  {
@@ -8247,6 +8240,7 @@ function App({ options, hostElement, bus }) {
8247
8240
  const markActiveConversationReadRef = useRef9(null);
8248
8241
  const markReadTimerRef = useRef9();
8249
8242
  useEffect16(() => () => clearTimeout(markReadTimerRef.current), []);
8243
+ const unreadIdsRef = useRef9(/* @__PURE__ */ new Set());
8250
8244
  useEffect16(() => {
8251
8245
  if (!conversationReady || homeNavSeeded.current) return;
8252
8246
  homeNavSeeded.current = true;
@@ -8446,18 +8440,11 @@ function App({ options, hostElement, bus }) {
8446
8440
  useEffect16(() => {
8447
8441
  if (effectiveLocale !== activeLocale) setActiveLocale(effectiveLocale);
8448
8442
  }, [effectiveLocale, activeLocale]);
8449
- const pendingSuggestionsRef = useRef9(null);
8450
8443
  const captureSuggestions = useCallback6((chunk) => {
8451
8444
  if (chunk.type !== "data-suggestions") return false;
8452
- pendingSuggestionsRef.current = parseSuggestions(chunk.data);
8445
+ setSuggestions(parseSuggestions(chunk.data));
8453
8446
  return true;
8454
8447
  }, []);
8455
- const flushSuggestions = useCallback6(() => {
8456
- if (pendingSuggestionsRef.current) {
8457
- setSuggestions(pendingSuggestionsRef.current);
8458
- pendingSuggestionsRef.current = null;
8459
- }
8460
- }, []);
8461
8448
  const adoptConversationRebind = useCallback6(
8462
8449
  (chunk) => {
8463
8450
  if (chunk.type !== "data-conversation-rebind") return false;
@@ -8477,7 +8464,6 @@ function App({ options, hostElement, bus }) {
8477
8464
  const runResume = useCallback6(
8478
8465
  async (handle) => {
8479
8466
  let bubble = null;
8480
- pendingSuggestionsRef.current = null;
8481
8467
  try {
8482
8468
  for await (const evt of handle.iter) {
8483
8469
  if (adoptConversationRebind(evt.chunk) || captureSuggestions(evt.chunk)) continue;
@@ -8506,7 +8492,6 @@ function App({ options, hostElement, bus }) {
8506
8492
  bubble.status = "complete";
8507
8493
  feedback.play("messageReceived");
8508
8494
  emitMessage(bus, options, "assistant", assistantText(bubble));
8509
- flushSuggestions();
8510
8495
  }
8511
8496
  }
8512
8497
  } catch (err) {
@@ -8646,7 +8631,6 @@ function App({ options, hostElement, bus }) {
8646
8631
  userPrefs: persistence.loadUserPrefs()
8647
8632
  });
8648
8633
  setStreaming(true);
8649
- pendingSuggestionsRef.current = null;
8650
8634
  const handle = transport.sendMessage(body);
8651
8635
  setActiveCancel(() => handle.cancel);
8652
8636
  setActiveDetach(() => handle.detach);
@@ -8671,7 +8655,6 @@ function App({ options, hostElement, bus }) {
8671
8655
  assistantMsg.status = "complete";
8672
8656
  feedback.play("messageReceived");
8673
8657
  emitMessage(bus, options, "assistant", assistantText(assistantMsg));
8674
- flushSuggestions();
8675
8658
  }
8676
8659
  } catch (error) {
8677
8660
  if (isAbortError(error)) {
@@ -8920,22 +8903,34 @@ function App({ options, hostElement, bus }) {
8920
8903
  bus.emit("close", void 0);
8921
8904
  options.onClose?.();
8922
8905
  }, [bus, options, persistence, panelSize, forms]);
8906
+ const recomputeUnread = useCallback6(() => {
8907
+ const onScreenConversationId = isChatActive() ? conversationIdSig.value : void 0;
8908
+ hasUnreadSig.value = [...unreadIdsRef.current].some((id) => id !== onScreenConversationId);
8909
+ }, [hasUnreadSig, conversationIdSig]);
8923
8910
  const refreshUnread = useCallback6(() => {
8924
8911
  if (!options.modules.list.some((m) => m.layout === "chat")) return;
8925
8912
  transport.listConversations({ limit: 50 }).then((res) => {
8926
- const onScreenConversationId = isChatActive() ? conversationIdSig.value : void 0;
8927
- hasUnreadSig.value = res.conversations.some((c) => c.hasUnread && c.conversationId !== onScreenConversationId);
8913
+ unreadIdsRef.current = new Set(res.conversations.filter((c) => c.hasUnread).map((c) => c.conversationId));
8914
+ recomputeUnread();
8928
8915
  }).catch((err) => log17.debug("refreshUnread failed (non-fatal)", { err }));
8929
- }, [transport, options.modules, hasUnreadSig, conversationIdSig]);
8916
+ }, [transport, options.modules, recomputeUnread]);
8917
+ const clearUnread = useCallback6(
8918
+ (conversationId) => {
8919
+ unreadIdsRef.current.delete(conversationId);
8920
+ recomputeUnread();
8921
+ },
8922
+ [recomputeUnread]
8923
+ );
8930
8924
  const markActiveConversationRead = useCallback6(() => {
8931
8925
  if (!isChatActive()) return;
8932
8926
  const conversationId = conversationIdSig.value;
8933
8927
  if (!conversationId) return;
8934
8928
  clearTimeout(markReadTimerRef.current);
8935
8929
  markReadTimerRef.current = setTimeout(() => {
8936
- void transport.markRead(conversationId).then(refreshUnread);
8930
+ clearUnread(conversationId);
8931
+ void transport.markRead(conversationId);
8937
8932
  }, MARK_READ_DELAY_MS);
8938
- }, [transport, conversationIdSig, refreshUnread]);
8933
+ }, [transport, conversationIdSig, clearUnread]);
8939
8934
  useEffect16(() => {
8940
8935
  markActiveConversationReadRef.current = markActiveConversationRead;
8941
8936
  }, [markActiveConversationRead]);
@@ -9082,7 +9077,7 @@ function App({ options, hostElement, bus }) {
9082
9077
  setView("chat");
9083
9078
  void resumeInFlight();
9084
9079
  await transport.markRead(targetConversationId);
9085
- refreshUnread();
9080
+ clearUnread(targetConversationId);
9086
9081
  } catch (err) {
9087
9082
  bus.emit("error", err);
9088
9083
  options.onError?.(err);
@@ -9095,7 +9090,7 @@ function App({ options, hostElement, bus }) {
9095
9090
  bus,
9096
9091
  options,
9097
9092
  persistence,
9098
- refreshUnread,
9093
+ clearUnread,
9099
9094
  fetchFormMarkers,
9100
9095
  withWelcomeRows,
9101
9096
  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.1"
83
+ "version": "0.61.3"
84
84
  }
package/web-component.mjs CHANGED
@@ -1930,7 +1930,7 @@ function createAuth(opts) {
1930
1930
  }
1931
1931
 
1932
1932
  // src/core/version.ts
1933
- var ELEMENTS_VERSION = true ? "0.61.1" : "0.0.0-dev";
1933
+ var ELEMENTS_VERSION = true ? "0.61.3" : "0.0.0-dev";
1934
1934
  var ELEMENTS_VERSION_PARAM = "_ev";
1935
1935
 
1936
1936
  // src/stream/types.ts
@@ -1962,7 +1962,7 @@ async function* parseChatStream(response, signal7) {
1962
1962
  const trailing = buffer.trim();
1963
1963
  if (trailing) {
1964
1964
  const parsed = parseFrame(trailing);
1965
- if (parsed) yield parsed;
1965
+ if (parsed && parsed !== "done") yield parsed;
1966
1966
  }
1967
1967
  return;
1968
1968
  }
@@ -1972,6 +1972,7 @@ async function* parseChatStream(response, signal7) {
1972
1972
  const frame = buffer.slice(0, frameEnd);
1973
1973
  buffer = buffer.slice(frameEnd + 2);
1974
1974
  const parsed = parseFrame(frame);
1975
+ if (parsed === "done") return;
1975
1976
  if (parsed) yield parsed;
1976
1977
  }
1977
1978
  }
@@ -1994,7 +1995,8 @@ ${part}` : part;
1994
1995
  eventId = line.slice(3).trim();
1995
1996
  }
1996
1997
  }
1997
- if (!dataPayload || dataPayload === "[DONE]") return null;
1998
+ if (dataPayload === "[DONE]") return "done";
1999
+ if (!dataPayload) return null;
1998
2000
  try {
1999
2001
  const chunk = JSON.parse(dataPayload);
2000
2002
  log4.trace("chunk", { type: chunk.type, eventId });
@@ -2197,7 +2199,6 @@ function messageToWireParts(m) {
2197
2199
  var log5 = logger.scope("transport");
2198
2200
  var MAX_RESUME_ATTEMPTS = 3;
2199
2201
  var RESUME_BACKOFF_MS = 400;
2200
- var POST_FINISH_DRAIN_MS = 2e4;
2201
2202
  var CONTENT_CACHE_TTL_MS = 6e4;
2202
2203
  var CONVERSATIONS_CACHE_TTL_MS = 1e4;
2203
2204
  var MAX_REQUEST_RETRIES = 3;
@@ -2711,11 +2712,6 @@ var AgentTransport = class {
2711
2712
  */
2712
2713
  async *drain(source, seenIds, ctrl) {
2713
2714
  let terminal = false;
2714
- let watchdog;
2715
- const armWatchdog = () => {
2716
- if (watchdog) clearTimeout(watchdog);
2717
- watchdog = setTimeout(() => ctrl.abort(), POST_FINISH_DRAIN_MS);
2718
- };
2719
2715
  try {
2720
2716
  for await (const evt of source) {
2721
2717
  if (ctrl.signal.aborted) return true;
@@ -2725,14 +2721,11 @@ var AgentTransport = class {
2725
2721
  }
2726
2722
  yield evt;
2727
2723
  if (evt.chunk.type === "finish" || evt.chunk.type === "error") terminal = true;
2728
- if (terminal) armWatchdog();
2729
2724
  }
2730
2725
  } catch (err) {
2731
2726
  if (ctrl.signal.aborted) return true;
2732
2727
  if (err instanceof StreamError && err.status !== void 0) throw err;
2733
2728
  log5.debug("stream segment dropped", { err });
2734
- } finally {
2735
- if (watchdog) clearTimeout(watchdog);
2736
2729
  }
2737
2730
  return terminal;
2738
2731
  }
@@ -6939,7 +6932,7 @@ function PanelContent(props2) {
6939
6932
  composerArea = null;
6940
6933
  } else if (canSend) {
6941
6934
  composerArea = /* @__PURE__ */ jsxs18(Fragment5, { children: [
6942
- /* @__PURE__ */ jsx23(Suggestions, { suggestions, onPick: onSuggestion }),
6935
+ !isStreaming && /* @__PURE__ */ jsx23(Suggestions, { suggestions, onPick: onSuggestion }),
6943
6936
  /* @__PURE__ */ jsx23(
6944
6937
  Composer,
6945
6938
  {
@@ -8206,6 +8199,7 @@ function App({ options, hostElement, bus }) {
8206
8199
  const markActiveConversationReadRef = useRef9(null);
8207
8200
  const markReadTimerRef = useRef9();
8208
8201
  useEffect16(() => () => clearTimeout(markReadTimerRef.current), []);
8202
+ const unreadIdsRef = useRef9(/* @__PURE__ */ new Set());
8209
8203
  useEffect16(() => {
8210
8204
  if (!conversationReady || homeNavSeeded.current) return;
8211
8205
  homeNavSeeded.current = true;
@@ -8405,18 +8399,11 @@ function App({ options, hostElement, bus }) {
8405
8399
  useEffect16(() => {
8406
8400
  if (effectiveLocale !== activeLocale) setActiveLocale(effectiveLocale);
8407
8401
  }, [effectiveLocale, activeLocale]);
8408
- const pendingSuggestionsRef = useRef9(null);
8409
8402
  const captureSuggestions = useCallback6((chunk) => {
8410
8403
  if (chunk.type !== "data-suggestions") return false;
8411
- pendingSuggestionsRef.current = parseSuggestions(chunk.data);
8404
+ setSuggestions(parseSuggestions(chunk.data));
8412
8405
  return true;
8413
8406
  }, []);
8414
- const flushSuggestions = useCallback6(() => {
8415
- if (pendingSuggestionsRef.current) {
8416
- setSuggestions(pendingSuggestionsRef.current);
8417
- pendingSuggestionsRef.current = null;
8418
- }
8419
- }, []);
8420
8407
  const adoptConversationRebind = useCallback6(
8421
8408
  (chunk) => {
8422
8409
  if (chunk.type !== "data-conversation-rebind") return false;
@@ -8436,7 +8423,6 @@ function App({ options, hostElement, bus }) {
8436
8423
  const runResume = useCallback6(
8437
8424
  async (handle) => {
8438
8425
  let bubble = null;
8439
- pendingSuggestionsRef.current = null;
8440
8426
  try {
8441
8427
  for await (const evt of handle.iter) {
8442
8428
  if (adoptConversationRebind(evt.chunk) || captureSuggestions(evt.chunk)) continue;
@@ -8465,7 +8451,6 @@ function App({ options, hostElement, bus }) {
8465
8451
  bubble.status = "complete";
8466
8452
  feedback.play("messageReceived");
8467
8453
  emitMessage(bus, options, "assistant", assistantText(bubble));
8468
- flushSuggestions();
8469
8454
  }
8470
8455
  }
8471
8456
  } catch (err) {
@@ -8605,7 +8590,6 @@ function App({ options, hostElement, bus }) {
8605
8590
  userPrefs: persistence.loadUserPrefs()
8606
8591
  });
8607
8592
  setStreaming(true);
8608
- pendingSuggestionsRef.current = null;
8609
8593
  const handle = transport.sendMessage(body);
8610
8594
  setActiveCancel(() => handle.cancel);
8611
8595
  setActiveDetach(() => handle.detach);
@@ -8630,7 +8614,6 @@ function App({ options, hostElement, bus }) {
8630
8614
  assistantMsg.status = "complete";
8631
8615
  feedback.play("messageReceived");
8632
8616
  emitMessage(bus, options, "assistant", assistantText(assistantMsg));
8633
- flushSuggestions();
8634
8617
  }
8635
8618
  } catch (error) {
8636
8619
  if (isAbortError(error)) {
@@ -8879,22 +8862,34 @@ function App({ options, hostElement, bus }) {
8879
8862
  bus.emit("close", void 0);
8880
8863
  options.onClose?.();
8881
8864
  }, [bus, options, persistence, panelSize, forms]);
8865
+ const recomputeUnread = useCallback6(() => {
8866
+ const onScreenConversationId = isChatActive() ? conversationIdSig.value : void 0;
8867
+ hasUnreadSig.value = [...unreadIdsRef.current].some((id) => id !== onScreenConversationId);
8868
+ }, [hasUnreadSig, conversationIdSig]);
8882
8869
  const refreshUnread = useCallback6(() => {
8883
8870
  if (!options.modules.list.some((m) => m.layout === "chat")) return;
8884
8871
  transport.listConversations({ limit: 50 }).then((res) => {
8885
- const onScreenConversationId = isChatActive() ? conversationIdSig.value : void 0;
8886
- hasUnreadSig.value = res.conversations.some((c) => c.hasUnread && c.conversationId !== onScreenConversationId);
8872
+ unreadIdsRef.current = new Set(res.conversations.filter((c) => c.hasUnread).map((c) => c.conversationId));
8873
+ recomputeUnread();
8887
8874
  }).catch((err) => log16.debug("refreshUnread failed (non-fatal)", { err }));
8888
- }, [transport, options.modules, hasUnreadSig, conversationIdSig]);
8875
+ }, [transport, options.modules, recomputeUnread]);
8876
+ const clearUnread = useCallback6(
8877
+ (conversationId) => {
8878
+ unreadIdsRef.current.delete(conversationId);
8879
+ recomputeUnread();
8880
+ },
8881
+ [recomputeUnread]
8882
+ );
8889
8883
  const markActiveConversationRead = useCallback6(() => {
8890
8884
  if (!isChatActive()) return;
8891
8885
  const conversationId = conversationIdSig.value;
8892
8886
  if (!conversationId) return;
8893
8887
  clearTimeout(markReadTimerRef.current);
8894
8888
  markReadTimerRef.current = setTimeout(() => {
8895
- void transport.markRead(conversationId).then(refreshUnread);
8889
+ clearUnread(conversationId);
8890
+ void transport.markRead(conversationId);
8896
8891
  }, MARK_READ_DELAY_MS);
8897
- }, [transport, conversationIdSig, refreshUnread]);
8892
+ }, [transport, conversationIdSig, clearUnread]);
8898
8893
  useEffect16(() => {
8899
8894
  markActiveConversationReadRef.current = markActiveConversationRead;
8900
8895
  }, [markActiveConversationRead]);
@@ -9041,7 +9036,7 @@ function App({ options, hostElement, bus }) {
9041
9036
  setView("chat");
9042
9037
  void resumeInFlight();
9043
9038
  await transport.markRead(targetConversationId);
9044
- refreshUnread();
9039
+ clearUnread(targetConversationId);
9045
9040
  } catch (err) {
9046
9041
  bus.emit("error", err);
9047
9042
  options.onError?.(err);
@@ -9054,7 +9049,7 @@ function App({ options, hostElement, bus }) {
9054
9049
  bus,
9055
9050
  options,
9056
9051
  persistence,
9057
- refreshUnread,
9052
+ clearUnread,
9058
9053
  fetchFormMarkers,
9059
9054
  withWelcomeRows,
9060
9055
  streaming,