@helpai/elements 0.61.4 → 0.61.5

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.4" : "0.0.0-dev";
32
+ var ELEMENTS_VERSION = true ? "0.61.5" : "0.0.0-dev";
33
33
  var ELEMENTS_VERSION_PARAM = "_ev";
34
34
 
35
35
  // src/i18n/strings.ts
@@ -2254,15 +2254,6 @@ function retryAfterMs(headers) {
2254
2254
  const ms = Number.isFinite(secs) ? secs * 1e3 : Date.parse(raw) - Date.now();
2255
2255
  return Number.isFinite(ms) && ms >= 0 ? Math.min(ms, 3e4) : null;
2256
2256
  }
2257
- function followupsFromMessages(messages) {
2258
- for (let i = messages.length - 1; i >= 0; i--) {
2259
- const m = messages[i];
2260
- if (!m || m.role !== "assistant") continue;
2261
- const part = m.parts.find((p36) => p36.type === "data-suggestions");
2262
- return part?.type === "data-suggestions" ? parseSuggestions(part.data) : void 0;
2263
- }
2264
- return void 0;
2265
- }
2266
2257
  function sleep(ms, signal7) {
2267
2258
  return new Promise((resolve) => {
2268
2259
  if (signal7?.aborted) return resolve();
@@ -2509,10 +2500,10 @@ var AgentTransport = class {
2509
2500
  canContinue: res.canContinue ?? true,
2510
2501
  messages,
2511
2502
  agent: res.agent,
2512
- // The latest turn's model follow-ups are persisted ON the assistant message (a `data-suggestions`
2513
- // part), not in a top-level field — read them off there, falling back to any server-provided
2514
- // top-level `suggestions` (e.g. resume chips) when the last turn carried none.
2515
- suggestions: followupsFromMessages(messages) ?? res.suggestions
2503
+ // Top-level STARTER chips (resume / new-chat), not turn-tied. A turn's own model follow-ups ride
2504
+ // ON its assistant message (`data-suggestions` part), lifted onto `message.suggestions` by
2505
+ // `fromWireMessage`; the App prefers the last turn's and falls back to these starters.
2506
+ suggestions: res.suggestions
2516
2507
  };
2517
2508
  }
2518
2509
  /**
@@ -3014,9 +3005,11 @@ function fromWireMessage(w) {
3014
3005
  }
3015
3006
  return null;
3016
3007
  }).filter((p36) => p36 !== null);
3008
+ const suggestionsPart = w.parts.find((p36) => p36.type === "data-suggestions");
3017
3009
  return {
3018
3010
  id: w.id,
3019
3011
  role: w.role,
3012
+ suggestions: suggestionsPart?.type === "data-suggestions" ? parseSuggestions(suggestionsPart.data) : void 0,
3020
3013
  // On reload the wire `id` IS the backend's id — keep it as `serverMessageId`
3021
3014
  // too so a HITL re-POST after a reload still references the backend's message.
3022
3015
  serverMessageId: w.id,
@@ -3239,6 +3232,7 @@ var StreamReducer = class {
3239
3232
  case "data-conversation-rebind":
3240
3233
  return;
3241
3234
  case "data-suggestions":
3235
+ m.suggestions = parseSuggestions(chunk.data);
3242
3236
  return;
3243
3237
  default: {
3244
3238
  const _exhaustive = chunk;
@@ -8305,7 +8299,8 @@ function App({ options, hostElement, bus }) {
8305
8299
  if (loaded.length || tail.length) {
8306
8300
  messagesSig.value = [...withWelcomeRows(loaded, markers), ...tail];
8307
8301
  setCanSend(chat.canContinue ?? true);
8308
- setSuggestions(chat.suggestions ?? []);
8302
+ const lastTurn = loaded.findLast((m) => m.role === "assistant" && !m.ephemeral);
8303
+ setSuggestions(lastTurn?.suggestions ?? chat.suggestions ?? []);
8309
8304
  } else {
8310
8305
  messagesSig.value = withWelcomeRows([], markers);
8311
8306
  }
@@ -8439,11 +8434,10 @@ function App({ options, hostElement, bus }) {
8439
8434
  useEffect16(() => {
8440
8435
  if (effectiveLocale !== activeLocale) setActiveLocale(effectiveLocale);
8441
8436
  }, [effectiveLocale, activeLocale]);
8442
- const captureSuggestions = useCallback6((chunk) => {
8443
- if (chunk.type !== "data-suggestions") return false;
8444
- setSuggestions(parseSuggestions(chunk.data));
8445
- return true;
8446
- }, []);
8437
+ const settleSuggestions = useCallback6(
8438
+ (turn, starters = []) => setSuggestions(turn.suggestions ?? starters),
8439
+ []
8440
+ );
8447
8441
  const adoptConversationRebind = useCallback6(
8448
8442
  (chunk) => {
8449
8443
  if (chunk.type !== "data-conversation-rebind") return false;
@@ -8465,7 +8459,7 @@ function App({ options, hostElement, bus }) {
8465
8459
  let bubble = null;
8466
8460
  try {
8467
8461
  for await (const evt of handle.iter) {
8468
- if (adoptConversationRebind(evt.chunk) || captureSuggestions(evt.chunk)) continue;
8462
+ if (adoptConversationRebind(evt.chunk)) continue;
8469
8463
  if (!bubble) {
8470
8464
  bubble = makeAssistantMessage();
8471
8465
  resumeBubbleRef.current = bubble;
@@ -8491,6 +8485,7 @@ function App({ options, hostElement, bus }) {
8491
8485
  bubble.status = "complete";
8492
8486
  feedback.play("messageReceived");
8493
8487
  emitMessage(bus, options, "assistant", assistantText(bubble));
8488
+ settleSuggestions(bubble);
8494
8489
  }
8495
8490
  }
8496
8491
  } catch (err) {
@@ -8635,7 +8630,7 @@ function App({ options, hostElement, bus }) {
8635
8630
  setActiveDetach(() => handle.detach);
8636
8631
  try {
8637
8632
  for await (const evt of handle.iter) {
8638
- if (adoptConversationRebind(evt.chunk) || captureSuggestions(evt.chunk)) continue;
8633
+ if (adoptConversationRebind(evt.chunk)) continue;
8639
8634
  reducer.apply(evt.chunk);
8640
8635
  if (evt.chunk.type === "finish" && evt.chunk.canContinue === false) {
8641
8636
  setCanSend(false);
@@ -8654,6 +8649,7 @@ function App({ options, hostElement, bus }) {
8654
8649
  assistantMsg.status = "complete";
8655
8650
  feedback.play("messageReceived");
8656
8651
  emitMessage(bus, options, "assistant", assistantText(assistantMsg));
8652
+ settleSuggestions(assistantMsg);
8657
8653
  }
8658
8654
  } catch (error) {
8659
8655
  if (isAbortError(error)) {
@@ -9072,7 +9068,8 @@ function App({ options, hostElement, bus }) {
9072
9068
  transport.primeIdentity(visitorId, res.conversationId);
9073
9069
  if (res.agent) setAgent(res.agent);
9074
9070
  setCanSend(res.canContinue);
9075
- setSuggestions(res.suggestions ?? []);
9071
+ const lastTurn = hydrated.findLast((m) => m.role === "assistant" && !m.ephemeral);
9072
+ setSuggestions(lastTurn?.suggestions ?? res.suggestions ?? []);
9076
9073
  setView("chat");
9077
9074
  void resumeInFlight();
9078
9075
  await transport.markRead(targetConversationId);
package/package.json CHANGED
@@ -80,5 +80,5 @@
80
80
  ],
81
81
  "type": "module",
82
82
  "types": "./index.d.ts",
83
- "version": "0.61.4"
83
+ "version": "0.61.5"
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.4" : "0.0.0-dev";
1933
+ var ELEMENTS_VERSION = true ? "0.61.5" : "0.0.0-dev";
1934
1934
  var ELEMENTS_VERSION_PARAM = "_ev";
1935
1935
 
1936
1936
  // src/stream/types.ts
@@ -2213,15 +2213,6 @@ function retryAfterMs(headers) {
2213
2213
  const ms = Number.isFinite(secs) ? secs * 1e3 : Date.parse(raw) - Date.now();
2214
2214
  return Number.isFinite(ms) && ms >= 0 ? Math.min(ms, 3e4) : null;
2215
2215
  }
2216
- function followupsFromMessages(messages) {
2217
- for (let i = messages.length - 1; i >= 0; i--) {
2218
- const m = messages[i];
2219
- if (!m || m.role !== "assistant") continue;
2220
- const part = m.parts.find((p36) => p36.type === "data-suggestions");
2221
- return part?.type === "data-suggestions" ? parseSuggestions(part.data) : void 0;
2222
- }
2223
- return void 0;
2224
- }
2225
2216
  function sleep(ms, signal7) {
2226
2217
  return new Promise((resolve) => {
2227
2218
  if (signal7?.aborted) return resolve();
@@ -2468,10 +2459,10 @@ var AgentTransport = class {
2468
2459
  canContinue: res.canContinue ?? true,
2469
2460
  messages,
2470
2461
  agent: res.agent,
2471
- // The latest turn's model follow-ups are persisted ON the assistant message (a `data-suggestions`
2472
- // part), not in a top-level field — read them off there, falling back to any server-provided
2473
- // top-level `suggestions` (e.g. resume chips) when the last turn carried none.
2474
- suggestions: followupsFromMessages(messages) ?? res.suggestions
2462
+ // Top-level STARTER chips (resume / new-chat), not turn-tied. A turn's own model follow-ups ride
2463
+ // ON its assistant message (`data-suggestions` part), lifted onto `message.suggestions` by
2464
+ // `fromWireMessage`; the App prefers the last turn's and falls back to these starters.
2465
+ suggestions: res.suggestions
2475
2466
  };
2476
2467
  }
2477
2468
  /**
@@ -2973,9 +2964,11 @@ function fromWireMessage(w) {
2973
2964
  }
2974
2965
  return null;
2975
2966
  }).filter((p36) => p36 !== null);
2967
+ const suggestionsPart = w.parts.find((p36) => p36.type === "data-suggestions");
2976
2968
  return {
2977
2969
  id: w.id,
2978
2970
  role: w.role,
2971
+ suggestions: suggestionsPart?.type === "data-suggestions" ? parseSuggestions(suggestionsPart.data) : void 0,
2979
2972
  // On reload the wire `id` IS the backend's id — keep it as `serverMessageId`
2980
2973
  // too so a HITL re-POST after a reload still references the backend's message.
2981
2974
  serverMessageId: w.id,
@@ -3198,6 +3191,7 @@ var StreamReducer = class {
3198
3191
  case "data-conversation-rebind":
3199
3192
  return;
3200
3193
  case "data-suggestions":
3194
+ m.suggestions = parseSuggestions(chunk.data);
3201
3195
  return;
3202
3196
  default: {
3203
3197
  const _exhaustive = chunk;
@@ -8264,7 +8258,8 @@ function App({ options, hostElement, bus }) {
8264
8258
  if (loaded.length || tail.length) {
8265
8259
  messagesSig.value = [...withWelcomeRows(loaded, markers), ...tail];
8266
8260
  setCanSend(chat.canContinue ?? true);
8267
- setSuggestions(chat.suggestions ?? []);
8261
+ const lastTurn = loaded.findLast((m) => m.role === "assistant" && !m.ephemeral);
8262
+ setSuggestions(lastTurn?.suggestions ?? chat.suggestions ?? []);
8268
8263
  } else {
8269
8264
  messagesSig.value = withWelcomeRows([], markers);
8270
8265
  }
@@ -8398,11 +8393,10 @@ function App({ options, hostElement, bus }) {
8398
8393
  useEffect16(() => {
8399
8394
  if (effectiveLocale !== activeLocale) setActiveLocale(effectiveLocale);
8400
8395
  }, [effectiveLocale, activeLocale]);
8401
- const captureSuggestions = useCallback6((chunk) => {
8402
- if (chunk.type !== "data-suggestions") return false;
8403
- setSuggestions(parseSuggestions(chunk.data));
8404
- return true;
8405
- }, []);
8396
+ const settleSuggestions = useCallback6(
8397
+ (turn, starters = []) => setSuggestions(turn.suggestions ?? starters),
8398
+ []
8399
+ );
8406
8400
  const adoptConversationRebind = useCallback6(
8407
8401
  (chunk) => {
8408
8402
  if (chunk.type !== "data-conversation-rebind") return false;
@@ -8424,7 +8418,7 @@ function App({ options, hostElement, bus }) {
8424
8418
  let bubble = null;
8425
8419
  try {
8426
8420
  for await (const evt of handle.iter) {
8427
- if (adoptConversationRebind(evt.chunk) || captureSuggestions(evt.chunk)) continue;
8421
+ if (adoptConversationRebind(evt.chunk)) continue;
8428
8422
  if (!bubble) {
8429
8423
  bubble = makeAssistantMessage();
8430
8424
  resumeBubbleRef.current = bubble;
@@ -8450,6 +8444,7 @@ function App({ options, hostElement, bus }) {
8450
8444
  bubble.status = "complete";
8451
8445
  feedback.play("messageReceived");
8452
8446
  emitMessage(bus, options, "assistant", assistantText(bubble));
8447
+ settleSuggestions(bubble);
8453
8448
  }
8454
8449
  }
8455
8450
  } catch (err) {
@@ -8594,7 +8589,7 @@ function App({ options, hostElement, bus }) {
8594
8589
  setActiveDetach(() => handle.detach);
8595
8590
  try {
8596
8591
  for await (const evt of handle.iter) {
8597
- if (adoptConversationRebind(evt.chunk) || captureSuggestions(evt.chunk)) continue;
8592
+ if (adoptConversationRebind(evt.chunk)) continue;
8598
8593
  reducer.apply(evt.chunk);
8599
8594
  if (evt.chunk.type === "finish" && evt.chunk.canContinue === false) {
8600
8595
  setCanSend(false);
@@ -8613,6 +8608,7 @@ function App({ options, hostElement, bus }) {
8613
8608
  assistantMsg.status = "complete";
8614
8609
  feedback.play("messageReceived");
8615
8610
  emitMessage(bus, options, "assistant", assistantText(assistantMsg));
8611
+ settleSuggestions(assistantMsg);
8616
8612
  }
8617
8613
  } catch (error) {
8618
8614
  if (isAbortError(error)) {
@@ -9031,7 +9027,8 @@ function App({ options, hostElement, bus }) {
9031
9027
  transport.primeIdentity(visitorId, res.conversationId);
9032
9028
  if (res.agent) setAgent(res.agent);
9033
9029
  setCanSend(res.canContinue);
9034
- setSuggestions(res.suggestions ?? []);
9030
+ const lastTurn = hydrated.findLast((m) => m.role === "assistant" && !m.ephemeral);
9031
+ setSuggestions(lastTurn?.suggestions ?? res.suggestions ?? []);
9035
9032
  setView("chat");
9036
9033
  void resumeInFlight();
9037
9034
  await transport.markRead(targetConversationId);