@helpai/elements 0.58.1 → 0.59.0

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/web-component.mjs CHANGED
@@ -85,7 +85,6 @@ var STRINGS_EN = {
85
85
  loading: "Loading\u2026",
86
86
  thinking: "Thinking\u2026",
87
87
  thoughts: "Thoughts",
88
- usedTool: "Used tool",
89
88
  toolResult: "Result",
90
89
  sources: "Sources",
91
90
  feedbackUp: "Good response",
@@ -156,12 +155,8 @@ var STRINGS_EN = {
156
155
  inputSkip: "Skip",
157
156
  confirmYes: "Yes",
158
157
  confirmNo: "No",
159
- approvalRequired: "Approval required",
160
158
  approve: "Approve",
161
159
  reject: "Reject",
162
- approved: "Approved",
163
- rejected: "Rejected",
164
- approvalReason: "Add a reason (optional)",
165
160
  approvalPrompt: "{tool} requires your approval to execute.",
166
161
  approvalBody: "Review the tool input above and decide whether to allow this action.",
167
162
  approvalYourResponse: "Your response: {decision}",
@@ -233,7 +228,6 @@ var STRINGS_FR = {
233
228
  loading: "Chargement\u2026",
234
229
  thinking: "R\xE9flexion\u2026",
235
230
  thoughts: "R\xE9flexions",
236
- usedTool: "Outil utilis\xE9",
237
231
  toolResult: "R\xE9sultat",
238
232
  sources: "Sources",
239
233
  feedbackUp: "Bonne r\xE9ponse",
@@ -304,12 +298,8 @@ var STRINGS_FR = {
304
298
  inputSkip: "Ignorer",
305
299
  confirmYes: "Oui",
306
300
  confirmNo: "Non",
307
- approvalRequired: "Approbation requise",
308
301
  approve: "Approuver",
309
302
  reject: "Refuser",
310
- approved: "Approuv\xE9",
311
- rejected: "Refus\xE9",
312
- approvalReason: "Ajouter une raison (facultatif)",
313
303
  approvalPrompt: "{tool} n\xE9cessite votre approbation pour s'ex\xE9cuter.",
314
304
  approvalBody: "V\xE9rifiez les param\xE8tres ci-dessus et d\xE9cidez d'autoriser ou non cette action.",
315
305
  approvalYourResponse: "Votre r\xE9ponse : {decision}",
@@ -381,7 +371,6 @@ var STRINGS_AR = {
381
371
  loading: "\u062C\u0627\u0631\u064D \u0627\u0644\u062A\u062D\u0645\u064A\u0644\u2026",
382
372
  thinking: "\u064A\u0641\u0643\u0651\u0631\u2026",
383
373
  thoughts: "\u0627\u0644\u0623\u0641\u0643\u0627\u0631",
384
- usedTool: "\u0623\u062F\u0627\u0629 \u0645\u064F\u0633\u062A\u062E\u062F\u064E\u0645\u0629",
385
374
  toolResult: "\u0627\u0644\u0646\u062A\u064A\u062C\u0629",
386
375
  sources: "\u0627\u0644\u0645\u0635\u0627\u062F\u0631",
387
376
  feedbackUp: "\u0631\u062F \u062C\u064A\u062F",
@@ -452,12 +441,8 @@ var STRINGS_AR = {
452
441
  inputSkip: "\u062A\u062E\u0637\u064D\u0651",
453
442
  confirmYes: "\u0646\u0639\u0645",
454
443
  confirmNo: "\u0644\u0627",
455
- approvalRequired: "\u0645\u0637\u0644\u0648\u0628 \u0645\u0648\u0627\u0641\u0642\u0629",
456
444
  approve: "\u0645\u0648\u0627\u0641\u0642\u0629",
457
445
  reject: "\u0631\u0641\u0636",
458
- approved: "\u062A\u0645\u062A \u0627\u0644\u0645\u0648\u0627\u0641\u0642\u0629",
459
- rejected: "\u0645\u0631\u0641\u0648\u0636",
460
- approvalReason: "\u0623\u0636\u0641 \u0633\u0628\u0628\u064B\u0627 (\u0627\u062E\u062A\u064A\u0627\u0631\u064A)",
461
446
  approvalPrompt: "\u062A\u062A\u0637\u0644\u0628 {tool} \u0645\u0648\u0627\u0641\u0642\u062A\u0643 \u0644\u0644\u062A\u0646\u0641\u064A\u0630.",
462
447
  approvalBody: "\u0631\u0627\u062C\u0639 \u0645\u064F\u0639\u0637\u064A\u0627\u062A \u0627\u0644\u0623\u062F\u0627\u0629 \u0623\u0639\u0644\u0627\u0647 \u0648\u0642\u0631\u0651\u0631 \u0627\u0644\u0633\u0645\u0627\u062D \u0628\u0647\u0630\u0627 \u0627\u0644\u0625\u062C\u0631\u0627\u0621 \u0623\u0648 \u0631\u0641\u0636\u0647.",
463
448
  approvalYourResponse: "\u0631\u062F\u0651\u0643: {decision}",
@@ -529,7 +514,6 @@ var STRINGS_ES = {
529
514
  loading: "Cargando\u2026",
530
515
  thinking: "Pensando\u2026",
531
516
  thoughts: "Razonamiento",
532
- usedTool: "Herramienta usada",
533
517
  toolResult: "Resultado",
534
518
  sources: "Fuentes",
535
519
  feedbackUp: "Buena respuesta",
@@ -600,12 +584,8 @@ var STRINGS_ES = {
600
584
  inputSkip: "Omitir",
601
585
  confirmYes: "S\xED",
602
586
  confirmNo: "No",
603
- approvalRequired: "Aprobaci\xF3n requerida",
604
587
  approve: "Aprobar",
605
588
  reject: "Rechazar",
606
- approved: "Aprobado",
607
- rejected: "Rechazado",
608
- approvalReason: "A\xF1ade un motivo (opcional)",
609
589
  approvalPrompt: "{tool} requiere tu aprobaci\xF3n para ejecutarse.",
610
590
  approvalBody: "Revisa los par\xE1metros de arriba y decide si permites esta acci\xF3n.",
611
591
  approvalYourResponse: "Tu respuesta: {decision}",
@@ -677,7 +657,6 @@ var STRINGS_HE = {
677
657
  loading: "\u05D8\u05D5\u05E2\u05DF\u2026",
678
658
  thinking: "\u05D7\u05D5\u05E9\u05D1\u2026",
679
659
  thoughts: "\u05DE\u05D7\u05E9\u05D1\u05D5\u05EA",
680
- usedTool: "\u05DB\u05DC\u05D9 \u05D1\u05E9\u05D9\u05DE\u05D5\u05E9",
681
660
  toolResult: "\u05EA\u05D5\u05E6\u05D0\u05D4",
682
661
  sources: "\u05DE\u05E7\u05D5\u05E8\u05D5\u05EA",
683
662
  feedbackUp: "\u05EA\u05E9\u05D5\u05D1\u05D4 \u05D8\u05D5\u05D1\u05D4",
@@ -748,12 +727,8 @@ var STRINGS_HE = {
748
727
  inputSkip: "\u05D3\u05D9\u05DC\u05D5\u05D2",
749
728
  confirmYes: "\u05DB\u05DF",
750
729
  confirmNo: "\u05DC\u05D0",
751
- approvalRequired: "\u05E0\u05D3\u05E8\u05E9 \u05D0\u05D9\u05E9\u05D5\u05E8",
752
730
  approve: "\u05D0\u05D9\u05E9\u05D5\u05E8",
753
731
  reject: "\u05D3\u05D7\u05D9\u05D9\u05D4",
754
- approved: "\u05D0\u05D5\u05E9\u05E8",
755
- rejected: "\u05E0\u05D3\u05D7\u05D4",
756
- approvalReason: "\u05D4\u05D5\u05E1\u05E3 \u05E1\u05D9\u05D1\u05D4 (\u05D0\u05D5\u05E4\u05E6\u05D9\u05D5\u05E0\u05DC\u05D9)",
757
732
  approvalPrompt: "\u05D4\u05DB\u05DC\u05D9 {tool} \u05D3\u05D5\u05E8\u05E9 \u05D0\u05EA \u05D0\u05D9\u05E9\u05D5\u05E8\u05DA \u05DB\u05D3\u05D9 \u05DC\u05E4\u05E2\u05D5\u05DC.",
758
733
  approvalBody: "\u05D1\u05D3\u05D5\u05E7 \u05D0\u05EA \u05E4\u05E8\u05DE\u05D8\u05E8\u05D9 \u05D4\u05DB\u05DC\u05D9 \u05E9\u05DC\u05DE\u05E2\u05DC\u05D4 \u05D5\u05D4\u05D7\u05DC\u05D8 \u05D0\u05DD \u05DC\u05D0\u05E9\u05E8 \u05E4\u05E2\u05D5\u05DC\u05D4 \u05D6\u05D5.",
759
734
  approvalYourResponse: "\u05D4\u05EA\u05D2\u05D5\u05D1\u05D4 \u05E9\u05DC\u05DA: {decision}",
@@ -1959,7 +1934,7 @@ function createAuth(opts) {
1959
1934
  }
1960
1935
 
1961
1936
  // src/core/version.ts
1962
- var ELEMENTS_VERSION = true ? "0.58.1" : "0.0.0-dev";
1937
+ var ELEMENTS_VERSION = true ? "0.59.0" : "0.0.0-dev";
1963
1938
  var ELEMENTS_VERSION_PARAM = "_ev";
1964
1939
 
1965
1940
  // src/stream/types.ts
@@ -3192,6 +3167,8 @@ var StreamReducer = class {
3192
3167
  return;
3193
3168
  case "data-conversation-rebind":
3194
3169
  return;
3170
+ case "data-suggestions":
3171
+ return;
3195
3172
  default: {
3196
3173
  const _exhaustive = chunk;
3197
3174
  void _exhaustive;
@@ -5612,6 +5589,12 @@ function toolDecisionState(state, approval) {
5612
5589
  const responded = state === "approval-responded" || approval?.approved !== void 0;
5613
5590
  return { terminal, responded, decided: terminal || responded };
5614
5591
  }
5592
+ function StatusPill({ status, icon, label }) {
5593
+ return /* @__PURE__ */ jsxs12("span", { class: `${p14}-toolui-badge ${p14}-toolui-status`, "data-status": status, children: [
5594
+ /* @__PURE__ */ jsx15("span", { class: `${p14}-toolui-status-icon`, children: icon }),
5595
+ label
5596
+ ] });
5597
+ }
5615
5598
  function statusOf(state, approval) {
5616
5599
  if (state === "output-error") return "error";
5617
5600
  if (state === "output-denied" || approval?.approved === false) return "denied";
@@ -5651,10 +5634,7 @@ function ToolStatus({
5651
5634
  }) {
5652
5635
  const base = statusOf(state, approval);
5653
5636
  const status = superseded && (base === "awaiting" || base === "running") ? "superseded" : base;
5654
- return /* @__PURE__ */ jsxs12("span", { class: `${p14}-toolui-badge ${p14}-toolui-status`, "data-status": status, children: [
5655
- /* @__PURE__ */ jsx15("span", { class: `${p14}-toolui-status-icon`, children: /* @__PURE__ */ jsx15(StatusIcon, { status }) }),
5656
- statusLabel(status, strings)
5657
- ] });
5637
+ return /* @__PURE__ */ jsx15(StatusPill, { status, icon: /* @__PURE__ */ jsx15(StatusIcon, { status }), label: statusLabel(status, strings) });
5658
5638
  }
5659
5639
  function ToolHeaderRow({
5660
5640
  name,
@@ -5879,18 +5859,18 @@ function ToolAskQuestions({ part, strings, active, superseded = false, onDecisio
5879
5859
  const req = useComputed4(() => parseAskUserQuestions(part.inputSig.value)).value;
5880
5860
  const { terminal, decided } = toolDecisionState(state, approval);
5881
5861
  const answered = decided && approval?.approved === true;
5882
- const editable = !decided && !superseded;
5883
- const skipped = !editable && !answered;
5862
+ const awaiting = !decided && !superseded;
5863
+ const skipped = !awaiting && !answered;
5884
5864
  const canEdit = answered && active && !terminal;
5885
5865
  const questions = req.questions;
5886
5866
  const [manualOpen, setManualOpen] = useState7(null);
5887
- const openDefault = editable || answered;
5867
+ const openDefault = awaiting || answered;
5888
5868
  const isOpen = manualOpen ?? openDefault;
5889
5869
  const [showOptions, setShowOptions] = useState7(false);
5890
5870
  const QIcon = questions.length > 1 ? ChatIcon : HelpIcon;
5891
- const identity = editable ? strings.inputRequired : strings.inputBadge;
5871
+ const identity = awaiting ? strings.inputRequired : strings.inputBadge;
5892
5872
  const body = (() => {
5893
- if (editable) {
5873
+ if (awaiting) {
5894
5874
  return /* @__PURE__ */ jsx17(EditableForm, { req, strings, resolve: (reason, ok) => onDecision(part.toolCallId, ok, reason) });
5895
5875
  }
5896
5876
  if (showOptions) {
@@ -5927,7 +5907,7 @@ function ToolAskQuestions({ part, strings, active, superseded = false, onDecisio
5927
5907
  const next = e.currentTarget.open;
5928
5908
  if (next !== isOpen) setManualOpen(next);
5929
5909
  },
5930
- "data-testid": editable ? TID.toolAskQuestions : TID.toolDecision,
5910
+ "data-testid": awaiting ? TID.toolAskQuestions : TID.toolDecision,
5931
5911
  children: [
5932
5912
  /* @__PURE__ */ jsxs14("summary", { class: `${p16}-toolui-head`, children: [
5933
5913
  /* @__PURE__ */ jsxs14("span", { class: `${p16}-toolui-q-pill`, children: [
@@ -5935,13 +5915,16 @@ function ToolAskQuestions({ part, strings, active, superseded = false, onDecisio
5935
5915
  identity
5936
5916
  ] }),
5937
5917
  /* @__PURE__ */ jsxs14("span", { class: `${p16}-toolui-head-end`, children: [
5938
- editable ? null : (
5939
- // Same neutral pill + coloured-icon status as the tool-call card
5940
- // (green check = answered, muted ✕ = skipped) — only the label differs.
5941
- /* @__PURE__ */ jsxs14("span", { class: `${p16}-toolui-badge ${p16}-toolui-status`, "data-status": skipped ? "superseded" : "completed", children: [
5942
- /* @__PURE__ */ jsx17("span", { class: `${p16}-toolui-status-icon`, children: skipped ? /* @__PURE__ */ jsx17(XCircleIcon, {}) : /* @__PURE__ */ jsx17(CheckCircleIcon, {}) }),
5943
- skipped ? strings.inputSkipped : strings.inputAnswered
5944
- ] })
5918
+ awaiting ? null : (
5919
+ // Reuse the tool-call status-pill shell green check = answered, muted ✕ = skipped.
5920
+ /* @__PURE__ */ jsx17(
5921
+ StatusPill,
5922
+ {
5923
+ status: skipped ? "superseded" : "completed",
5924
+ icon: skipped ? /* @__PURE__ */ jsx17(XCircleIcon, {}) : /* @__PURE__ */ jsx17(CheckCircleIcon, {}),
5925
+ label: skipped ? strings.inputSkipped : strings.inputAnswered
5926
+ }
5927
+ )
5945
5928
  ),
5946
5929
  /* @__PURE__ */ jsx17("span", { class: `${p16}-toolui-chevron`, children: /* @__PURE__ */ jsx17(ChevronDownIcon, {}) })
5947
5930
  ] })
@@ -5949,7 +5932,7 @@ function ToolAskQuestions({ part, strings, active, superseded = false, onDecisio
5949
5932
  /* @__PURE__ */ jsxs14("div", { class: `${p16}-toolui-collapse-body`, children: [
5950
5933
  req.intro ? /* @__PURE__ */ jsx17("div", { class: `${p16}-toolui-desc`, children: req.intro }) : null,
5951
5934
  body,
5952
- editable ? null : /* @__PURE__ */ jsxs14(
5935
+ awaiting ? null : /* @__PURE__ */ jsxs14(
5953
5936
  "button",
5954
5937
  {
5955
5938
  type: "button",
@@ -6816,6 +6799,22 @@ function ConversationList({
6816
6799
  // src/ui/suggestions.tsx
6817
6800
  import { jsx as jsx22 } from "preact/jsx-runtime";
6818
6801
  var p19 = BRAND.cssPrefix;
6802
+ function parseSuggestions(data) {
6803
+ const raw = data?.suggestions;
6804
+ if (!Array.isArray(raw)) return [];
6805
+ const out = [];
6806
+ for (const item of raw) {
6807
+ if (!item || typeof item !== "object") continue;
6808
+ const { id, label, text } = item;
6809
+ if (typeof label !== "string" || !label) continue;
6810
+ out.push({
6811
+ id: typeof id === "string" && id ? id : `s${out.length}`,
6812
+ label,
6813
+ text: typeof text === "string" && text ? text : label
6814
+ });
6815
+ }
6816
+ return out;
6817
+ }
6819
6818
  function Suggestions({ suggestions, onPick }) {
6820
6819
  if (suggestions.length === 0) return null;
6821
6820
  return /* @__PURE__ */ jsx22("div", { class: `${p19}-suggestions`, role: "group", "aria-label": "Suggested replies", children: suggestions.map((s, i) => /* @__PURE__ */ jsx22(
@@ -8385,6 +8384,18 @@ function App({ options, hostElement, bus }) {
8385
8384
  useEffect16(() => {
8386
8385
  if (effectiveLocale !== activeLocale) setActiveLocale(effectiveLocale);
8387
8386
  }, [effectiveLocale, activeLocale]);
8387
+ const pendingSuggestionsRef = useRef9(null);
8388
+ const captureSuggestions = useCallback6((chunk) => {
8389
+ if (chunk.type !== "data-suggestions") return false;
8390
+ pendingSuggestionsRef.current = parseSuggestions(chunk.data);
8391
+ return true;
8392
+ }, []);
8393
+ const flushSuggestions = useCallback6(() => {
8394
+ if (pendingSuggestionsRef.current) {
8395
+ setSuggestions(pendingSuggestionsRef.current);
8396
+ pendingSuggestionsRef.current = null;
8397
+ }
8398
+ }, []);
8388
8399
  const adoptConversationRebind = useCallback6(
8389
8400
  (chunk) => {
8390
8401
  if (chunk.type !== "data-conversation-rebind") return false;
@@ -8404,9 +8415,10 @@ function App({ options, hostElement, bus }) {
8404
8415
  const runResume = useCallback6(
8405
8416
  async (handle) => {
8406
8417
  let bubble = null;
8418
+ pendingSuggestionsRef.current = null;
8407
8419
  try {
8408
8420
  for await (const evt of handle.iter) {
8409
- if (adoptConversationRebind(evt.chunk)) continue;
8421
+ if (adoptConversationRebind(evt.chunk) || captureSuggestions(evt.chunk)) continue;
8410
8422
  if (!bubble) {
8411
8423
  bubble = makeAssistantMessage();
8412
8424
  resumeBubbleRef.current = bubble;
@@ -8432,6 +8444,7 @@ function App({ options, hostElement, bus }) {
8432
8444
  bubble.status = "complete";
8433
8445
  feedback.play("messageReceived");
8434
8446
  emitMessage(bus, options, "assistant", assistantText(bubble));
8447
+ flushSuggestions();
8435
8448
  }
8436
8449
  }
8437
8450
  } catch (err) {
@@ -8570,12 +8583,13 @@ function App({ options, hostElement, bus }) {
8570
8583
  userPrefs: persistence.loadUserPrefs()
8571
8584
  });
8572
8585
  setStreaming(true);
8586
+ pendingSuggestionsRef.current = null;
8573
8587
  const handle = transport.sendMessage(body);
8574
8588
  setActiveCancel(() => handle.cancel);
8575
8589
  setActiveDetach(() => handle.detach);
8576
8590
  try {
8577
8591
  for await (const evt of handle.iter) {
8578
- if (adoptConversationRebind(evt.chunk)) continue;
8592
+ if (adoptConversationRebind(evt.chunk) || captureSuggestions(evt.chunk)) continue;
8579
8593
  reducer.apply(evt.chunk);
8580
8594
  if (evt.chunk.type === "finish" && evt.chunk.canContinue === false) {
8581
8595
  setCanSend(false);
@@ -8594,6 +8608,7 @@ function App({ options, hostElement, bus }) {
8594
8608
  assistantMsg.status = "complete";
8595
8609
  feedback.play("messageReceived");
8596
8610
  emitMessage(bus, options, "assistant", assistantText(assistantMsg));
8611
+ flushSuggestions();
8597
8612
  }
8598
8613
  } catch (error) {
8599
8614
  if (isAbortError(error)) {