@xinghunm/ai-chat 1.0.1 → 1.1.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/dist/index.mjs CHANGED
@@ -42,7 +42,10 @@ var DEFAULT_AI_CHAT_LABELS = {
42
42
  questionnaireSubmitting: "Submitting...",
43
43
  questionnaireSubmitted: "Selection submitted. Waiting for the plan to continue...",
44
44
  questionnaireValidationPrefix: "Please complete:",
45
- questionnaireSubmitFailed: "Failed to submit. Please try again."
45
+ questionnaireSubmitFailed: "Failed to submit. Please try again.",
46
+ questionnaireMultiSelectHint: "Multiple choice",
47
+ questionnaireOtherOptionLabel: "Other",
48
+ questionnaireOtherPlaceholder: "Other"
46
49
  };
47
50
 
48
51
  // src/store/chat-store.ts
@@ -77,6 +80,22 @@ var mergeStreamingBlocks = (existingBlocks, incomingBlocks) => {
77
80
  nextBlocks.push(incomingBlock);
78
81
  return;
79
82
  }
83
+ if (incomingBlock.type === "questionnaire" && incomingBlock.questionnaire.blockKey) {
84
+ const mergePolicy = incomingBlock.questionnaire.mergePolicy ?? "append";
85
+ if (mergePolicy !== "append") {
86
+ const existingIndex2 = nextBlocks.findIndex(
87
+ (block) => block.type === "questionnaire" && block.questionnaire.blockKey === incomingBlock.questionnaire.blockKey
88
+ );
89
+ if (existingIndex2 !== -1) {
90
+ if (mergePolicy === "replace") {
91
+ nextBlocks[existingIndex2] = incomingBlock;
92
+ }
93
+ return;
94
+ }
95
+ }
96
+ nextBlocks.push(incomingBlock);
97
+ return;
98
+ }
80
99
  if (incomingBlock.type !== "questionnaire") {
81
100
  nextBlocks.push(incomingBlock);
82
101
  return;
@@ -679,7 +698,7 @@ var AiChatProvider = (props) => {
679
698
  };
680
699
 
681
700
  // src/components/chat-thread/index.tsx
682
- import { useCallback as useCallback3, useLayoutEffect as useLayoutEffect2, useMemo as useMemo4, useRef as useRef4, useState as useState4 } from "react";
701
+ import { useCallback as useCallback3, useLayoutEffect as useLayoutEffect2, useMemo as useMemo4, useRef as useRef5, useState as useState4 } from "react";
683
702
  import styled9 from "@emotion/styled";
684
703
 
685
704
  // src/context/use-chat-context.ts
@@ -977,7 +996,7 @@ var getTimelineBlockKey = (block, index) => {
977
996
  case "result_summary":
978
997
  return `${index}:result_summary:${block.summary.summaryId}:${block.summary.status}`;
979
998
  case "questionnaire":
980
- return `${index}:questionnaire:${block.questionnaire.questionnaireId}`;
999
+ return block.questionnaire.blockKey ? `questionnaire:${block.questionnaire.blockKey}` : `${index}:questionnaire:${block.questionnaire.questionnaireId}`;
981
1000
  case "custom":
982
1001
  return block.blockKey ? `custom:${block.blockKey}` : `${index}:custom:${block.kind}:${stringifyTimelineKeyPart(block.data)}`;
983
1002
  default:
@@ -1469,31 +1488,126 @@ var Value = styled3.span`
1469
1488
  `;
1470
1489
 
1471
1490
  // src/components/chat-thread/components/questionnaire-card.tsx
1472
- import { useState as useState2 } from "react";
1491
+ import {
1492
+ useEffect as useEffect3,
1493
+ useRef as useRef3,
1494
+ useState as useState2
1495
+ } from "react";
1473
1496
  import styled4 from "@emotion/styled";
1474
- import { jsx as jsx5, jsxs as jsxs3 } from "@emotion/react/jsx-runtime";
1497
+ import { InputField } from "@xinghunm/compass-ui";
1498
+
1499
+ // src/components/chat-thread/components/questionnaire-card-helpers.ts
1475
1500
  var OTHER_OPTION_VALUE = "__other__";
1476
- var DEFAULT_QUESTIONNAIRE_CARD_LABELS = {
1477
- submitting: "Submitting...",
1478
- submitted: "Selection submitted. Waiting for the plan to continue...",
1479
- validationPrefix: "Please complete:",
1480
- submitFailed: "Failed to submit. Please try again."
1481
- };
1482
- var createInitialAnswers = (questionnaire) => ({
1483
- ...questionnaire.answers ?? {}
1484
- });
1501
+ var getQuestionnaireQuestion = (questionnaire) => questionnaire.question;
1485
1502
  var getMultiSelectAnswerValues = (answer) => Array.isArray(answer) ? answer : [];
1486
- var getSingleSelectDraftState = (question, answer) => {
1503
+ var getQuestionOptionValues = (question) => new Set(question.options.map((option) => option.value));
1504
+ var extractSingleSelectOtherDraft = (question, answer) => {
1505
+ if (typeof answer !== "string") {
1506
+ return "";
1507
+ }
1508
+ return getQuestionOptionValues(question).has(answer) ? "" : answer;
1509
+ };
1510
+ var extractMultiSelectOtherDraft = (question, answer) => {
1511
+ if (!Array.isArray(answer)) {
1512
+ return "";
1513
+ }
1514
+ const optionValues = getQuestionOptionValues(question);
1515
+ const customValue = answer.find(
1516
+ (value) => typeof value === "string" && value !== OTHER_OPTION_VALUE && !optionValues.has(value)
1517
+ );
1518
+ return typeof customValue === "string" ? customValue : "";
1519
+ };
1520
+ var createInitialAnswers = (questionnaire) => {
1521
+ const initialAnswers = {};
1522
+ const question = getQuestionnaireQuestion(questionnaire);
1523
+ if (!question) {
1524
+ return initialAnswers;
1525
+ }
1526
+ const answer = questionnaire.answers?.[question.id];
1527
+ switch (question.kind) {
1528
+ case "single_select": {
1529
+ if (typeof answer !== "string") {
1530
+ break;
1531
+ }
1532
+ if (getQuestionOptionValues(question).has(answer)) {
1533
+ initialAnswers[question.id] = answer;
1534
+ break;
1535
+ }
1536
+ if (question.allowOther) {
1537
+ initialAnswers[question.id] = OTHER_OPTION_VALUE;
1538
+ }
1539
+ break;
1540
+ }
1541
+ case "multi_select": {
1542
+ if (!Array.isArray(answer)) {
1543
+ break;
1544
+ }
1545
+ const optionValues = getQuestionOptionValues(question);
1546
+ const selectedValues = [];
1547
+ let hasOtherValue = false;
1548
+ for (const value of answer) {
1549
+ if (typeof value !== "string") {
1550
+ continue;
1551
+ }
1552
+ if (optionValues.has(value)) {
1553
+ selectedValues.push(value);
1554
+ continue;
1555
+ }
1556
+ if (question.allowOther && !hasOtherValue) {
1557
+ selectedValues.push(OTHER_OPTION_VALUE);
1558
+ hasOtherValue = true;
1559
+ }
1560
+ }
1561
+ initialAnswers[question.id] = selectedValues;
1562
+ break;
1563
+ }
1564
+ default:
1565
+ initialAnswers[question.id] = answer;
1566
+ }
1567
+ return initialAnswers;
1568
+ };
1569
+ var createInitialOtherDrafts = (questionnaire) => {
1570
+ const drafts = {};
1571
+ const question = getQuestionnaireQuestion(questionnaire);
1572
+ if (!question) {
1573
+ return drafts;
1574
+ }
1575
+ const answer = questionnaire.answers?.[question.id];
1576
+ switch (question.kind) {
1577
+ case "single_select":
1578
+ if (question.allowOther) {
1579
+ drafts[question.id] = extractSingleSelectOtherDraft(question, answer);
1580
+ }
1581
+ break;
1582
+ case "multi_select":
1583
+ if (question.allowOther) {
1584
+ drafts[question.id] = extractMultiSelectOtherDraft(question, answer);
1585
+ }
1586
+ break;
1587
+ default:
1588
+ break;
1589
+ }
1590
+ return drafts;
1591
+ };
1592
+ var getMultiSelectDraftState = (question, answer, otherDraft) => {
1593
+ const answerValues = getMultiSelectAnswerValues(answer);
1594
+ return {
1595
+ selectedValues: answerValues,
1596
+ otherValue: otherDraft,
1597
+ hasOtherSelected: question.allowOther === true && answerValues.includes(OTHER_OPTION_VALUE)
1598
+ };
1599
+ };
1600
+ var getSingleSelectDraftState = (question, answer, otherDraft) => {
1487
1601
  if (typeof answer !== "string") {
1488
1602
  return {
1489
1603
  selectedValue: void 0,
1490
- otherValue: ""
1604
+ otherValue: otherDraft
1491
1605
  };
1492
1606
  }
1493
- const matchesOption = question.options.some((option) => option.value === answer);
1607
+ const matchesOption = answer !== OTHER_OPTION_VALUE && question.options.some((option) => option.value === answer);
1494
1608
  return {
1495
1609
  selectedValue: matchesOption ? answer : question.allowOther ? OTHER_OPTION_VALUE : void 0,
1496
- otherValue: matchesOption ? "" : answer
1610
+ otherValue: otherDraft
1497
1611
  };
1498
1612
  };
1499
1613
  var updateAnswerValue = (current, questionId, value) => ({
@@ -1505,6 +1619,17 @@ var toggleMultiSelectAnswer = (current, questionId, optionValue) => {
1505
1619
  const nextValues = currentValues.includes(optionValue) ? currentValues.filter((value) => value !== optionValue) : [...currentValues, optionValue];
1506
1620
  return updateAnswerValue(current, questionId, nextValues);
1507
1621
  };
1622
+ var toggleMultiSelectOtherAnswer = (current, question) => {
1623
+ const currentValues = getMultiSelectAnswerValues(current[question.id]);
1624
+ if (currentValues.includes(OTHER_OPTION_VALUE)) {
1625
+ return updateAnswerValue(
1626
+ current,
1627
+ question.id,
1628
+ currentValues.filter((value) => value !== OTHER_OPTION_VALUE)
1629
+ );
1630
+ }
1631
+ return updateAnswerValue(current, question.id, [...currentValues, OTHER_OPTION_VALUE]);
1632
+ };
1508
1633
  var getTextInputValue = (answer) => typeof answer === "string" ? String(answer) : "";
1509
1634
  var getNumberInputValue = (answer) => typeof answer === "number" || typeof answer === "string" ? String(answer) : "";
1510
1635
  var getOptionChoiceLabel = (index) => {
@@ -1513,20 +1638,49 @@ var getOptionChoiceLabel = (index) => {
1513
1638
  }
1514
1639
  return String(index + 1);
1515
1640
  };
1516
- var isMissingRequiredAnswer = (question, answers) => {
1517
- const answer = answers[question.id];
1641
+ var normalizeQuestionAnswer = (question, answer, otherDraft = "") => {
1642
+ if (answer === void 0) {
1643
+ return void 0;
1644
+ }
1518
1645
  switch (question.kind) {
1519
- case "boolean":
1520
- return typeof answer !== "boolean";
1521
1646
  case "multi_select":
1522
- return !Array.isArray(answer) || answer.length === 0;
1523
- case "number":
1524
- return typeof answer !== "number" || Number.isNaN(answer);
1525
- case "text":
1647
+ if (!Array.isArray(answer)) {
1648
+ return void 0;
1649
+ }
1650
+ return (() => {
1651
+ const optionValues = getQuestionOptionValues(question);
1652
+ const normalizedOtherDraft = otherDraft.trim();
1653
+ const normalizedValues = answer.flatMap((value) => {
1654
+ if (typeof value !== "string") {
1655
+ return [];
1656
+ }
1657
+ if (optionValues.has(value)) {
1658
+ return [value];
1659
+ }
1660
+ if (!question.allowOther || value !== OTHER_OPTION_VALUE) {
1661
+ return [];
1662
+ }
1663
+ return normalizedOtherDraft === "" ? [] : [normalizedOtherDraft];
1664
+ });
1665
+ return normalizedValues.length > 0 ? normalizedValues : void 0;
1666
+ })();
1526
1667
  case "single_select":
1527
- return typeof answer !== "string" || answer.trim() === "";
1668
+ if (answer === OTHER_OPTION_VALUE) {
1669
+ const normalizedOtherDraft = otherDraft.trim();
1670
+ return normalizedOtherDraft === "" ? void 0 : normalizedOtherDraft;
1671
+ }
1672
+ if (typeof answer !== "string" || answer.trim() === "") {
1673
+ return void 0;
1674
+ }
1675
+ return getQuestionOptionValues(question).has(answer) ? answer : void 0;
1676
+ case "text":
1677
+ return typeof answer === "string" && answer.trim() !== "" ? answer : void 0;
1678
+ case "number":
1679
+ return typeof answer === "number" && !Number.isNaN(answer) ? answer : void 0;
1680
+ case "boolean":
1681
+ return typeof answer === "boolean" ? answer : void 0;
1528
1682
  default:
1529
- return true;
1683
+ return answer;
1530
1684
  }
1531
1685
  };
1532
1686
  var formatQuestionAnswer = (question, answer) => {
@@ -1554,79 +1708,221 @@ var formatQuestionAnswer = (question, answer) => {
1554
1708
  return String(answer);
1555
1709
  }
1556
1710
  };
1557
- var normalizeQuestionAnswer = (question, answer) => {
1711
+ var buildQuestionSubmissionDetail = (question, answer) => {
1558
1712
  if (answer === void 0) {
1559
1713
  return void 0;
1560
1714
  }
1561
1715
  switch (question.kind) {
1562
- case "multi_select":
1563
- return Array.isArray(answer) && answer.length > 0 ? answer : void 0;
1564
- case "single_select":
1565
- case "text":
1566
- return typeof answer === "string" && answer.trim() !== "" ? answer : void 0;
1567
- case "number":
1568
- return typeof answer === "number" && !Number.isNaN(answer) ? answer : void 0;
1569
- case "boolean":
1570
- return typeof answer === "boolean" ? answer : void 0;
1716
+ case "single_select": {
1717
+ if (typeof answer !== "string") {
1718
+ return void 0;
1719
+ }
1720
+ const optionValues = getQuestionOptionValues(question);
1721
+ const trimmedAnswer = answer.trim();
1722
+ return {
1723
+ questionId: question.id,
1724
+ kind: question.kind,
1725
+ value: answer,
1726
+ selectedOptionValues: optionValues.has(answer) ? [answer] : [],
1727
+ otherValue: optionValues.has(answer) || trimmedAnswer === "" ? void 0 : trimmedAnswer
1728
+ };
1729
+ }
1730
+ case "multi_select": {
1731
+ if (!Array.isArray(answer)) {
1732
+ return void 0;
1733
+ }
1734
+ const optionValues = getQuestionOptionValues(question);
1735
+ const selectedOptionValues = answer.filter(
1736
+ (value) => typeof value === "string" && optionValues.has(value)
1737
+ );
1738
+ const otherValue = answer.find(
1739
+ (value) => typeof value === "string" && !optionValues.has(value)
1740
+ );
1741
+ return {
1742
+ questionId: question.id,
1743
+ kind: question.kind,
1744
+ value: answer,
1745
+ selectedOptionValues,
1746
+ otherValue: otherValue?.trim() ? otherValue.trim() : void 0
1747
+ };
1748
+ }
1571
1749
  default:
1572
- return answer;
1750
+ return {
1751
+ questionId: question.id,
1752
+ kind: question.kind,
1753
+ value: answer
1754
+ };
1755
+ }
1756
+ };
1757
+ var getMissingRequiredQuestions = (questionnaire, answers, otherDrafts) => {
1758
+ const question = getQuestionnaireQuestion(questionnaire);
1759
+ if (!question || !question.required) {
1760
+ return [];
1573
1761
  }
1762
+ return normalizeQuestionAnswer(question, answers[question.id], otherDrafts[question.id]) === void 0 ? [question] : [];
1763
+ };
1764
+ var prepareQuestionnaireSubmission = (questionnaire, answers, otherDrafts) => {
1765
+ const question = getQuestionnaireQuestion(questionnaire);
1766
+ if (!question) {
1767
+ return {
1768
+ normalizedAnswers: {},
1769
+ submissionDetails: void 0,
1770
+ content: questionnaire.title ?? "Questionnaire responses"
1771
+ };
1772
+ }
1773
+ const value = normalizeQuestionAnswer(question, answers[question.id], otherDrafts[question.id]);
1774
+ const normalizedAnswers = value === void 0 ? {} : { [question.id]: value };
1775
+ const detail = buildQuestionSubmissionDetail(question, normalizedAnswers[question.id]);
1776
+ const submissionDetails = detail === void 0 ? void 0 : { [question.id]: detail };
1777
+ return {
1778
+ normalizedAnswers,
1779
+ submissionDetails,
1780
+ content: [
1781
+ questionnaire.title ?? "Questionnaire responses",
1782
+ ...normalizedAnswers[question.id] === void 0 ? [] : [
1783
+ `- ${question.label}: ${formatQuestionAnswer(question, normalizedAnswers[question.id])}`
1784
+ ]
1785
+ ].join("\n")
1786
+ };
1787
+ };
1788
+ var getQuestionnaireStateKey = (questionnaire) => JSON.stringify([
1789
+ questionnaire.questionnaireId,
1790
+ questionnaire.blockKey,
1791
+ questionnaire.question,
1792
+ questionnaire.status,
1793
+ questionnaire.statusMessage
1794
+ ]);
1795
+
1796
+ // src/components/chat-thread/components/questionnaire-card.tsx
1797
+ import { jsx as jsx5, jsxs as jsxs3 } from "@emotion/react/jsx-runtime";
1798
+ var DEFAULT_QUESTIONNAIRE_CARD_LABELS = {
1799
+ submitting: "Submitting...",
1800
+ submitted: "Selection submitted. Waiting for the plan to continue...",
1801
+ validationPrefix: "Please complete:",
1802
+ submitFailed: "Failed to submit. Please try again.",
1803
+ multiSelectHint: "Multiple choice",
1804
+ otherOptionLabel: "Other",
1805
+ otherPlaceholder: "Other"
1806
+ };
1807
+ var stopInputClickPropagation = (event) => {
1808
+ event.stopPropagation();
1574
1809
  };
1810
+ var stopInputKeyPropagation = (event) => {
1811
+ event.stopPropagation();
1812
+ };
1813
+ var OptionChoice = ({
1814
+ questionId,
1815
+ optionLabel,
1816
+ index,
1817
+ isSelected,
1818
+ isInteractionLocked,
1819
+ onClick,
1820
+ inlineInput,
1821
+ tone = "default"
1822
+ }) => /* @__PURE__ */ jsxs3(
1823
+ OptionChoiceItem,
1824
+ {
1825
+ role: "button",
1826
+ tabIndex: isInteractionLocked ? -1 : 0,
1827
+ "aria-pressed": isSelected,
1828
+ "data-selected": isSelected,
1829
+ "data-tone": tone,
1830
+ "data-testid": `question-option-${questionId}-${index}`,
1831
+ onClick: (event) => {
1832
+ if (isInteractionLocked) {
1833
+ return;
1834
+ }
1835
+ if (event.target instanceof HTMLElement && event.target.closest("input")) {
1836
+ return;
1837
+ }
1838
+ onClick();
1839
+ },
1840
+ onKeyDown: (event) => {
1841
+ if (isInteractionLocked) {
1842
+ return;
1843
+ }
1844
+ if (event.key !== "Enter" && event.key !== " ") {
1845
+ return;
1846
+ }
1847
+ event.preventDefault();
1848
+ onClick();
1849
+ },
1850
+ children: [
1851
+ /* @__PURE__ */ jsx5(OptionChoiceMarker, { "data-selected": isSelected, children: getOptionChoiceLabel(index) }),
1852
+ /* @__PURE__ */ jsxs3(OptionChoiceContent, { children: [
1853
+ inlineInput ? null : /* @__PURE__ */ jsx5(OptionChoiceLabel, { children: optionLabel }),
1854
+ inlineInput
1855
+ ] })
1856
+ ]
1857
+ }
1858
+ );
1575
1859
  var QuestionnaireCardInner = ({
1576
1860
  questionnaire,
1577
1861
  interactive = false,
1578
1862
  onSubmit,
1579
1863
  labels
1580
1864
  }) => {
1865
+ const questionnaireRef = useRef3(questionnaire);
1866
+ const otherInputRefs = useRef3({});
1581
1867
  const [answers, setAnswers] = useState2(
1582
1868
  () => createInitialAnswers(questionnaire)
1583
1869
  );
1870
+ const [otherDrafts, setOtherDrafts] = useState2(
1871
+ () => createInitialOtherDrafts(questionnaire)
1872
+ );
1584
1873
  const [errorMessage, setErrorMessage] = useState2(null);
1585
1874
  const [isSubmitting, setIsSubmitting] = useState2(false);
1586
1875
  const [isSubmitted, setIsSubmitted] = useState2(false);
1876
+ const [pendingFocusQuestionId, setPendingFocusQuestionId] = useState2(null);
1587
1877
  const resolvedLabels = {
1588
1878
  ...DEFAULT_QUESTIONNAIRE_CARD_LABELS,
1589
1879
  ...labels
1590
1880
  };
1591
1881
  const hasExternalFailureStatus = questionnaire.status === "expired" || questionnaire.status === "failed";
1882
+ const question = getQuestionnaireQuestion(questionnaire);
1592
1883
  const visibleErrorMessage = questionnaire.statusMessage ?? errorMessage;
1593
1884
  const isInteractionLocked = !interactive || isSubmitting || isSubmitted || hasExternalFailureStatus;
1885
+ questionnaireRef.current = questionnaire;
1886
+ useEffect3(() => {
1887
+ setAnswers(createInitialAnswers(questionnaireRef.current));
1888
+ setOtherDrafts(createInitialOtherDrafts(questionnaireRef.current));
1889
+ }, [questionnaire.answers]);
1890
+ useEffect3(() => {
1891
+ if (!pendingFocusQuestionId || isInteractionLocked) {
1892
+ return;
1893
+ }
1894
+ const inputElement = otherInputRefs.current[pendingFocusQuestionId];
1895
+ if (!inputElement) {
1896
+ return;
1897
+ }
1898
+ inputElement.focus();
1899
+ setPendingFocusQuestionId(null);
1900
+ }, [isInteractionLocked, pendingFocusQuestionId]);
1594
1901
  const handleSubmit = async () => {
1595
1902
  if (isSubmitting || isSubmitted) {
1596
1903
  return;
1597
1904
  }
1598
- const missingQuestions = questionnaire.questions.filter(
1599
- (question) => question.required && isMissingRequiredAnswer(question, answers)
1600
- );
1905
+ const missingQuestions = getMissingRequiredQuestions(questionnaire, answers, otherDrafts);
1601
1906
  if (missingQuestions.length > 0) {
1602
1907
  setErrorMessage(
1603
- `${resolvedLabels.validationPrefix} ${missingQuestions.map((question) => question.label).join(", ")}`
1908
+ `${resolvedLabels.validationPrefix} ${missingQuestions.map((question2) => question2.label).join(", ")}`
1604
1909
  );
1605
1910
  return;
1606
1911
  }
1607
1912
  setErrorMessage(null);
1608
1913
  setIsSubmitting(true);
1609
- const normalizedAnswers = Object.fromEntries(
1610
- questionnaire.questions.flatMap((question) => {
1611
- const value = normalizeQuestionAnswer(question, answers[question.id]);
1612
- return value === void 0 ? [] : [[question.id, value]];
1613
- })
1914
+ const { normalizedAnswers, submissionDetails, content } = prepareQuestionnaireSubmission(
1915
+ questionnaire,
1916
+ answers,
1917
+ otherDrafts
1614
1918
  );
1615
- const contentLines = [
1616
- questionnaire.title ?? "Questionnaire responses",
1617
- ...questionnaire.questions.flatMap((question) => {
1618
- const value = normalizedAnswers[question.id];
1619
- if (value === void 0) {
1620
- return [];
1621
- }
1622
- return [`- ${question.label}: ${formatQuestionAnswer(question, value)}`];
1623
- })
1624
- ];
1625
1919
  try {
1626
1920
  await onSubmit?.({
1627
1921
  questionnaireId: questionnaire.questionnaireId,
1922
+ ...questionnaire.blockKey ? { blockKey: questionnaire.blockKey } : {},
1628
1923
  answers: normalizedAnswers,
1629
- content: contentLines.join("\n")
1924
+ details: submissionDetails,
1925
+ content
1630
1926
  });
1631
1927
  setIsSubmitted(true);
1632
1928
  } catch (error) {
@@ -1635,125 +1931,156 @@ var QuestionnaireCardInner = ({
1635
1931
  setIsSubmitting(false);
1636
1932
  }
1637
1933
  };
1638
- const renderQuestion = (question) => {
1639
- const renderOptionChoice = ({
1640
- questionId,
1641
- optionLabel,
1642
- index,
1643
- isSelected,
1644
- onClick,
1645
- inlineInput,
1646
- tone = "default"
1647
- }) => /* @__PURE__ */ jsxs3(
1648
- OptionChoiceItem,
1649
- {
1650
- role: "button",
1651
- tabIndex: isInteractionLocked ? -1 : 0,
1652
- "aria-pressed": isSelected,
1653
- "data-selected": isSelected,
1654
- "data-tone": tone,
1655
- "data-testid": `question-option-${questionId}-${index}`,
1656
- onClick: (event) => {
1657
- if (isInteractionLocked) {
1658
- return;
1659
- }
1660
- if (event.target instanceof HTMLElement && event.target.closest("input")) {
1661
- return;
1662
- }
1663
- onClick();
1664
- },
1665
- onKeyDown: (event) => {
1666
- if (isInteractionLocked) {
1667
- return;
1668
- }
1669
- if (event.key !== "Enter" && event.key !== " ") {
1670
- return;
1671
- }
1672
- event.preventDefault();
1673
- onClick();
1674
- },
1675
- children: [
1676
- /* @__PURE__ */ jsx5(OptionChoiceMarker, { "data-selected": isSelected, children: getOptionChoiceLabel(index) }),
1677
- /* @__PURE__ */ jsxs3(OptionChoiceContent, { children: [
1678
- inlineInput ? null : /* @__PURE__ */ jsx5(OptionChoiceLabel, { children: optionLabel }),
1679
- inlineInput
1680
- ] })
1681
- ]
1682
- },
1683
- `${questionId}-${optionLabel}`
1684
- );
1685
- switch (question.kind) {
1686
- case "multi_select":
1687
- return /* @__PURE__ */ jsx5(QuestionBody, { children: /* @__PURE__ */ jsx5(OptionList, { children: question.options.map((option, index) => {
1688
- const selectedValues = getMultiSelectAnswerValues(answers[question.id]);
1689
- const isSelected = selectedValues.includes(option.value);
1690
- return renderOptionChoice({
1691
- questionId: question.id,
1692
- optionLabel: option.label,
1693
- index,
1694
- isSelected,
1695
- onClick: () => setAnswers(
1696
- (current) => toggleMultiSelectAnswer(current, question.id, option.value)
1697
- )
1698
- });
1699
- }) }) });
1934
+ if (!question) {
1935
+ return null;
1936
+ }
1937
+ const renderQuestion = (questionToRender) => {
1938
+ switch (questionToRender.kind) {
1939
+ case "multi_select": {
1940
+ const multiSelectDraft = getMultiSelectDraftState(
1941
+ questionToRender,
1942
+ answers[questionToRender.id],
1943
+ otherDrafts[questionToRender.id] ?? ""
1944
+ );
1945
+ return /* @__PURE__ */ jsx5(QuestionBody, { children: /* @__PURE__ */ jsxs3(OptionList, { children: [
1946
+ questionToRender.options.map((option, index) => {
1947
+ const isSelected = multiSelectDraft.selectedValues.includes(option.value);
1948
+ return /* @__PURE__ */ jsx5(
1949
+ OptionChoice,
1950
+ {
1951
+ questionId: questionToRender.id,
1952
+ optionLabel: option.label,
1953
+ index,
1954
+ isSelected,
1955
+ isInteractionLocked,
1956
+ onClick: () => setAnswers(
1957
+ (current) => toggleMultiSelectAnswer(current, questionToRender.id, option.value)
1958
+ )
1959
+ },
1960
+ option.value
1961
+ );
1962
+ }),
1963
+ questionToRender.allowOther ? /* @__PURE__ */ jsx5(
1964
+ OptionChoice,
1965
+ {
1966
+ questionId: questionToRender.id,
1967
+ optionLabel: resolvedLabels.otherOptionLabel,
1968
+ index: questionToRender.options.length,
1969
+ isSelected: multiSelectDraft.hasOtherSelected,
1970
+ isInteractionLocked,
1971
+ tone: "other",
1972
+ onClick: () => {
1973
+ if (!multiSelectDraft.hasOtherSelected) {
1974
+ setPendingFocusQuestionId(questionToRender.id);
1975
+ }
1976
+ setAnswers((current) => toggleMultiSelectOtherAnswer(current, questionToRender));
1977
+ },
1978
+ inlineInput: multiSelectDraft.hasOtherSelected ? /* @__PURE__ */ jsx5(
1979
+ InlineOtherInput,
1980
+ {
1981
+ ref: (node) => {
1982
+ otherInputRefs.current[questionToRender.id] = node;
1983
+ },
1984
+ "data-testid": `question-input-${questionToRender.id}`,
1985
+ type: "text",
1986
+ value: multiSelectDraft.otherValue,
1987
+ placeholder: resolvedLabels.otherPlaceholder,
1988
+ readOnly: isInteractionLocked,
1989
+ onClick: stopInputClickPropagation,
1990
+ onKeyDown: stopInputKeyPropagation,
1991
+ onChange: (event) => {
1992
+ setOtherDrafts((current) => ({
1993
+ ...current,
1994
+ [questionToRender.id]: event.target.value
1995
+ }));
1996
+ }
1997
+ }
1998
+ ) : null
1999
+ },
2000
+ `${questionToRender.id}-other`
2001
+ ) : null
2002
+ ] }) });
2003
+ }
1700
2004
  case "single_select": {
1701
- const singleSelectDraft = getSingleSelectDraftState(question, answers[question.id]);
2005
+ const singleSelectDraft = getSingleSelectDraftState(
2006
+ questionToRender,
2007
+ answers[questionToRender.id],
2008
+ otherDrafts[questionToRender.id] ?? ""
2009
+ );
1702
2010
  return /* @__PURE__ */ jsx5(QuestionBody, { children: /* @__PURE__ */ jsxs3(OptionList, { children: [
1703
- question.options.map((option, index) => {
2011
+ questionToRender.options.map((option, index) => {
1704
2012
  const isSelected = singleSelectDraft.selectedValue === option.value;
1705
- return renderOptionChoice({
1706
- questionId: question.id,
1707
- optionLabel: option.label,
1708
- index,
1709
- isSelected,
1710
- onClick: () => setAnswers((current) => updateAnswerValue(current, question.id, option.value))
1711
- });
1712
- }),
1713
- question.allowOther ? renderOptionChoice({
1714
- questionId: question.id,
1715
- optionLabel: "Other",
1716
- index: question.options.length,
1717
- isSelected: singleSelectDraft.selectedValue === OTHER_OPTION_VALUE,
1718
- tone: "other",
1719
- onClick: () => setAnswers(
1720
- (current) => updateAnswerValue(current, question.id, singleSelectDraft.otherValue)
1721
- ),
1722
- inlineInput: singleSelectDraft.selectedValue === OTHER_OPTION_VALUE ? /* @__PURE__ */ jsx5(
1723
- InlineOtherInput,
2013
+ return /* @__PURE__ */ jsx5(
2014
+ OptionChoice,
1724
2015
  {
1725
- "data-testid": `question-input-${question.id}`,
1726
- type: "text",
1727
- value: singleSelectDraft.otherValue,
1728
- placeholder: "Other",
1729
- readOnly: isInteractionLocked,
1730
- onClick: (event) => {
1731
- event.stopPropagation();
1732
- },
1733
- onKeyDown: (event) => {
1734
- event.stopPropagation();
1735
- },
1736
- onChange: (event) => {
1737
- setAnswers(
1738
- (current) => updateAnswerValue(current, question.id, event.target.value)
1739
- );
2016
+ questionId: questionToRender.id,
2017
+ optionLabel: option.label,
2018
+ index,
2019
+ isSelected,
2020
+ isInteractionLocked,
2021
+ onClick: () => setAnswers(
2022
+ (current) => updateAnswerValue(current, questionToRender.id, option.value)
2023
+ )
2024
+ },
2025
+ option.value
2026
+ );
2027
+ }),
2028
+ questionToRender.allowOther ? /* @__PURE__ */ jsx5(
2029
+ OptionChoice,
2030
+ {
2031
+ questionId: questionToRender.id,
2032
+ optionLabel: resolvedLabels.otherOptionLabel,
2033
+ index: questionToRender.options.length,
2034
+ isSelected: singleSelectDraft.selectedValue === OTHER_OPTION_VALUE,
2035
+ isInteractionLocked,
2036
+ tone: "other",
2037
+ onClick: () => {
2038
+ if (singleSelectDraft.selectedValue !== OTHER_OPTION_VALUE) {
2039
+ setPendingFocusQuestionId(questionToRender.id);
1740
2040
  }
1741
- }
1742
- ) : null
1743
- }) : null
2041
+ setAnswers(
2042
+ (current) => updateAnswerValue(current, questionToRender.id, OTHER_OPTION_VALUE)
2043
+ );
2044
+ },
2045
+ inlineInput: singleSelectDraft.selectedValue === OTHER_OPTION_VALUE ? /* @__PURE__ */ jsx5(
2046
+ InlineOtherInput,
2047
+ {
2048
+ ref: (node) => {
2049
+ otherInputRefs.current[questionToRender.id] = node;
2050
+ },
2051
+ "data-testid": `question-input-${questionToRender.id}`,
2052
+ type: "text",
2053
+ value: singleSelectDraft.otherValue,
2054
+ placeholder: resolvedLabels.otherPlaceholder,
2055
+ readOnly: isInteractionLocked,
2056
+ onClick: stopInputClickPropagation,
2057
+ onKeyDown: stopInputKeyPropagation,
2058
+ onChange: (event) => {
2059
+ setOtherDrafts((current) => ({
2060
+ ...current,
2061
+ [questionToRender.id]: event.target.value
2062
+ }));
2063
+ }
2064
+ }
2065
+ ) : null
2066
+ },
2067
+ `${questionToRender.id}-other`
2068
+ ) : null
1744
2069
  ] }) });
1745
2070
  }
1746
2071
  case "text":
1747
2072
  return /* @__PURE__ */ jsx5(QuestionBody, { children: /* @__PURE__ */ jsx5(
1748
2073
  TextInput,
1749
2074
  {
1750
- "data-testid": `question-input-${question.id}`,
2075
+ "data-testid": `question-input-${questionToRender.id}`,
1751
2076
  type: "text",
1752
- value: getTextInputValue(answers[question.id]),
1753
- placeholder: question.placeholder,
2077
+ value: getTextInputValue(answers[questionToRender.id]),
2078
+ placeholder: questionToRender.placeholder,
1754
2079
  readOnly: isInteractionLocked,
1755
2080
  onChange: (event) => {
1756
- setAnswers((current) => updateAnswerValue(current, question.id, event.target.value));
2081
+ setAnswers(
2082
+ (current) => updateAnswerValue(current, questionToRender.id, event.target.value)
2083
+ );
1757
2084
  }
1758
2085
  }
1759
2086
  ) });
@@ -1762,55 +2089,63 @@ var QuestionnaireCardInner = ({
1762
2089
  /* @__PURE__ */ jsx5(
1763
2090
  TextInput,
1764
2091
  {
1765
- "data-testid": `question-input-${question.id}`,
2092
+ "data-testid": `question-input-${questionToRender.id}`,
1766
2093
  type: "number",
1767
- value: getNumberInputValue(answers[question.id]),
1768
- placeholder: question.placeholder,
2094
+ value: getNumberInputValue(answers[questionToRender.id]),
2095
+ placeholder: questionToRender.placeholder,
1769
2096
  readOnly: isInteractionLocked,
1770
2097
  onChange: (event) => {
1771
2098
  setAnswers(
1772
2099
  (current) => updateAnswerValue(
1773
2100
  current,
1774
- question.id,
2101
+ questionToRender.id,
1775
2102
  event.target.value === "" ? void 0 : Number(event.target.value)
1776
2103
  )
1777
2104
  );
1778
2105
  }
1779
2106
  }
1780
2107
  ),
1781
- question.unit ? /* @__PURE__ */ jsx5(Unit, { children: question.unit }) : null
2108
+ questionToRender.unit ? /* @__PURE__ */ jsx5(Unit, { children: questionToRender.unit }) : null
1782
2109
  ] }) });
1783
2110
  case "boolean":
1784
2111
  return /* @__PURE__ */ jsx5(QuestionBody, { children: /* @__PURE__ */ jsxs3(OptionList, { children: [
1785
- renderOptionChoice({
1786
- questionId: question.id,
1787
- optionLabel: question.trueLabel ?? "Yes",
1788
- index: 0,
1789
- isSelected: answers[question.id] === true,
1790
- onClick: () => setAnswers((current) => updateAnswerValue(current, question.id, true))
1791
- }),
1792
- renderOptionChoice({
1793
- questionId: question.id,
1794
- optionLabel: question.falseLabel ?? "No",
1795
- index: 1,
1796
- isSelected: answers[question.id] === false,
1797
- onClick: () => setAnswers((current) => updateAnswerValue(current, question.id, false))
1798
- })
2112
+ /* @__PURE__ */ jsx5(
2113
+ OptionChoice,
2114
+ {
2115
+ questionId: questionToRender.id,
2116
+ optionLabel: questionToRender.trueLabel ?? "Yes",
2117
+ index: 0,
2118
+ isSelected: answers[questionToRender.id] === true,
2119
+ isInteractionLocked,
2120
+ onClick: () => setAnswers((current) => updateAnswerValue(current, questionToRender.id, true))
2121
+ }
2122
+ ),
2123
+ /* @__PURE__ */ jsx5(
2124
+ OptionChoice,
2125
+ {
2126
+ questionId: questionToRender.id,
2127
+ optionLabel: questionToRender.falseLabel ?? "No",
2128
+ index: 1,
2129
+ isSelected: answers[questionToRender.id] === false,
2130
+ isInteractionLocked,
2131
+ onClick: () => setAnswers((current) => updateAnswerValue(current, questionToRender.id, false))
2132
+ }
2133
+ )
1799
2134
  ] }) });
1800
2135
  default:
1801
2136
  return null;
1802
2137
  }
1803
2138
  };
1804
2139
  return /* @__PURE__ */ jsxs3(Card4, { "data-testid": "questionnaire-card", children: [
1805
- questionnaire.title ? /* @__PURE__ */ jsx5(Title3, { children: questionnaire.title }) : null,
1806
2140
  questionnaire.description ? /* @__PURE__ */ jsx5(Description, { children: questionnaire.description }) : null,
1807
- /* @__PURE__ */ jsx5(QuestionList, { children: questionnaire.questions.map((question) => /* @__PURE__ */ jsxs3(QuestionCard, { children: [
2141
+ /* @__PURE__ */ jsx5(QuestionList, { children: /* @__PURE__ */ jsxs3(QuestionCard, { children: [
1808
2142
  /* @__PURE__ */ jsxs3(QuestionLabel, { children: [
1809
2143
  question.label,
1810
2144
  question.required ? /* @__PURE__ */ jsx5(Required, { children: "*" }) : null
1811
2145
  ] }),
2146
+ question.kind === "multi_select" ? /* @__PURE__ */ jsx5(QuestionHint, { children: resolvedLabels.multiSelectHint }) : null,
1812
2147
  renderQuestion(question)
1813
- ] }, question.id)) }),
2148
+ ] }, question.id) }),
1814
2149
  visibleErrorMessage ? /* @__PURE__ */ jsx5(ErrorMessage, { "data-testid": "questionnaire-error", children: visibleErrorMessage }) : null,
1815
2150
  isSubmitted ? /* @__PURE__ */ jsx5(SuccessMessage, { "data-testid": "questionnaire-success", children: resolvedLabels.submitted }) : interactive && !hasExternalFailureStatus ? /* @__PURE__ */ jsx5(
1816
2151
  SubmitButton,
@@ -1826,12 +2161,6 @@ var QuestionnaireCardInner = ({
1826
2161
  ) : null
1827
2162
  ] });
1828
2163
  };
1829
- var getQuestionnaireStateKey = (questionnaire) => JSON.stringify([
1830
- questionnaire.questionnaireId,
1831
- questionnaire.questions,
1832
- questionnaire.status,
1833
- questionnaire.statusMessage
1834
- ]);
1835
2164
  var QuestionnaireCard = (props) => /* @__PURE__ */ jsx5(QuestionnaireCardInner, { ...props }, getQuestionnaireStateKey(props.questionnaire));
1836
2165
  var Card4 = styled4.section`
1837
2166
  display: grid;
@@ -1841,11 +2170,6 @@ var Card4 = styled4.section`
1841
2170
  border: 1px solid rgba(255, 255, 255, 0.08);
1842
2171
  background: rgba(255, 255, 255, 0.03);
1843
2172
  `;
1844
- var Title3 = styled4.strong`
1845
- color: rgba(255, 255, 255, 0.94);
1846
- font-size: 16px;
1847
- line-height: 1.4;
1848
- `;
1849
2173
  var Description = styled4.p`
1850
2174
  margin: 0;
1851
2175
  color: rgba(255, 255, 255, 0.72);
@@ -1864,13 +2188,18 @@ var QuestionCard = styled4.div`
1864
2188
  `;
1865
2189
  var QuestionLabel = styled4.div`
1866
2190
  color: rgba(255, 255, 255, 0.9);
1867
- font-size: 13px;
2191
+ font-size: 14px;
1868
2192
  font-weight: 600;
1869
2193
  `;
1870
2194
  var Required = styled4.span`
1871
2195
  margin-left: 4px;
1872
2196
  color: rgba(255, 122, 122, 0.9);
1873
2197
  `;
2198
+ var QuestionHint = styled4.div`
2199
+ color: rgba(132, 180, 255, 0.9);
2200
+ font-size: 12px;
2201
+ line-height: 1.4;
2202
+ `;
1874
2203
  var QuestionBody = styled4.div`
1875
2204
  display: grid;
1876
2205
  gap: 10px;
@@ -1888,7 +2217,7 @@ var OptionChoiceItem = styled4.div`
1888
2217
  border: 1px solid rgba(255, 255, 255, 0.1);
1889
2218
  border-radius: 14px;
1890
2219
  background: rgba(255, 255, 255, 0.03);
1891
- padding: 12px 14px;
2220
+ padding: 2px 12px;
1892
2221
  color: rgba(255, 255, 255, 0.9);
1893
2222
  cursor: pointer;
1894
2223
  transition:
@@ -1939,8 +2268,11 @@ var OptionChoiceMarker = styled4.span`
1939
2268
  }
1940
2269
  `;
1941
2270
  var OptionChoiceContent = styled4.span`
1942
- display: grid;
1943
- gap: 2px;
2271
+ display: flex;
2272
+ flex-direction: column;
2273
+ justify-content: center;
2274
+ gap: 4px;
2275
+ min-height: 40px;
1944
2276
  min-width: 0;
1945
2277
  flex: 1;
1946
2278
  `;
@@ -1963,8 +2295,37 @@ var TextInput = styled4.input`
1963
2295
  color: rgba(255, 255, 255, 0.34);
1964
2296
  }
1965
2297
  `;
1966
- var InlineOtherInput = styled4(TextInput)`
2298
+ var InlineOtherInput = styled4(InputField)`
2299
+ width: 100%;
1967
2300
  margin-top: 0;
2301
+
2302
+ .compass-input-field-wrapper {
2303
+ min-height: 30px;
2304
+ border: 1px solid rgba(255, 255, 255, 0.1);
2305
+ border-radius: 10px;
2306
+ background: rgba(13, 15, 21, 0.55);
2307
+ box-shadow: none;
2308
+ padding: 2px 9px;
2309
+ }
2310
+
2311
+ .compass-input-field-wrapper:hover {
2312
+ border-color: rgba(126, 160, 255, 0.28);
2313
+ }
2314
+
2315
+ .compass-input-field-wrapper:focus-within {
2316
+ border-color: rgba(126, 160, 255, 0.42);
2317
+ box-shadow: 0 0 0 1px rgba(126, 160, 255, 0.14);
2318
+ }
2319
+
2320
+ .compass-input-field-input {
2321
+ color: rgba(255, 255, 255, 0.92);
2322
+ font-size: 13px;
2323
+ line-height: 1.2;
2324
+ }
2325
+
2326
+ .compass-input-field-input::placeholder {
2327
+ color: rgba(255, 255, 255, 0.34);
2328
+ }
1968
2329
  `;
1969
2330
  var NumberInputRow = styled4.div`
1970
2331
  display: flex;
@@ -2050,7 +2411,7 @@ var Detail = styled5.li`
2050
2411
 
2051
2412
  // src/components/chat-thread/components/image-viewer.tsx
2052
2413
  import styled6 from "@emotion/styled";
2053
- import { useEffect as useEffect3, useRef as useRef3 } from "react";
2414
+ import { useEffect as useEffect4, useRef as useRef4 } from "react";
2054
2415
  import { jsx as jsx7 } from "@emotion/react/jsx-runtime";
2055
2416
  var Overlay = styled6.div`
2056
2417
  position: fixed;
@@ -2069,8 +2430,8 @@ var Img = styled6.img`
2069
2430
  border-radius: 4px;
2070
2431
  `;
2071
2432
  var ImageViewer = ({ src, alt, onClose }) => {
2072
- const overlayRef = useRef3(null);
2073
- useEffect3(() => {
2433
+ const overlayRef = useRef4(null);
2434
+ useEffect4(() => {
2074
2435
  const handleKey = (e) => {
2075
2436
  if (e.key === "Escape")
2076
2437
  onClose();
@@ -2078,7 +2439,7 @@ var ImageViewer = ({ src, alt, onClose }) => {
2078
2439
  document.addEventListener("keydown", handleKey);
2079
2440
  return () => document.removeEventListener("keydown", handleKey);
2080
2441
  }, [onClose]);
2081
- useEffect3(() => {
2442
+ useEffect4(() => {
2082
2443
  overlayRef.current?.focus();
2083
2444
  }, []);
2084
2445
  const stopPropagation = (e) => e.stopPropagation();
@@ -2273,9 +2634,7 @@ var arePlanQuestionsEqual = (previousQuestion, nextQuestion) => {
2273
2634
  return false;
2274
2635
  }
2275
2636
  };
2276
- var areQuestionnairesEqual = (previousQuestionnaire, nextQuestionnaire) => previousQuestionnaire.questionnaireId === nextQuestionnaire.questionnaireId && previousQuestionnaire.title === nextQuestionnaire.title && previousQuestionnaire.description === nextQuestionnaire.description && previousQuestionnaire.submitLabel === nextQuestionnaire.submitLabel && previousQuestionnaire.status === nextQuestionnaire.status && previousQuestionnaire.statusMessage === nextQuestionnaire.statusMessage && previousQuestionnaire.questions.length === nextQuestionnaire.questions.length && previousQuestionnaire.questions.every(
2277
- (question, index) => arePlanQuestionsEqual(question, nextQuestionnaire.questions[index])
2278
- ) && areQuestionAnswerMapsEqual(previousQuestionnaire.answers, nextQuestionnaire.answers);
2637
+ var areQuestionnairesEqual = (previousQuestionnaire, nextQuestionnaire) => previousQuestionnaire.questionnaireId === nextQuestionnaire.questionnaireId && previousQuestionnaire.title === nextQuestionnaire.title && previousQuestionnaire.description === nextQuestionnaire.description && previousQuestionnaire.submitLabel === nextQuestionnaire.submitLabel && previousQuestionnaire.status === nextQuestionnaire.status && previousQuestionnaire.statusMessage === nextQuestionnaire.statusMessage && arePlanQuestionsEqual(previousQuestionnaire.question, nextQuestionnaire.question) && areQuestionAnswerMapsEqual(previousQuestionnaire.answers, nextQuestionnaire.answers);
2279
2638
  var areMessageBlocksEqual = (previousBlocks, nextBlocks) => {
2280
2639
  if (previousBlocks === nextBlocks) {
2281
2640
  return true;
@@ -2429,14 +2788,17 @@ var ChatMessageItemView = ({
2429
2788
  submitting: labels.questionnaireSubmitting,
2430
2789
  submitted: labels.questionnaireSubmitted,
2431
2790
  validationPrefix: labels.questionnaireValidationPrefix,
2432
- submitFailed: labels.questionnaireSubmitFailed
2791
+ submitFailed: labels.questionnaireSubmitFailed,
2792
+ multiSelectHint: labels.questionnaireMultiSelectHint,
2793
+ otherOptionLabel: labels.questionnaireOtherOptionLabel,
2794
+ otherPlaceholder: labels.questionnaireOtherPlaceholder
2433
2795
  },
2434
2796
  onSubmit: canSubmitQuestionnaire ? (submission) => onQuestionnaireSubmit({
2435
2797
  ...submission,
2436
2798
  sourceMessageId: message.id
2437
2799
  }) : void 0
2438
2800
  }
2439
- ) }, `questionnaire-${index}`);
2801
+ ) }, block.questionnaire.blockKey ?? `questionnaire-${index}`);
2440
2802
  case "custom":
2441
2803
  return /* @__PURE__ */ jsx8(Fragment, { children: renderMessageBlock?.({
2442
2804
  block,
@@ -2688,8 +3050,34 @@ var CollapseToggle = styled7.button`
2688
3050
  `;
2689
3051
  var Content = styled7.div`
2690
3052
  color: rgba(255, 255, 255, 0.92);
3053
+ font-size: 14px;
2691
3054
  line-height: 1.6;
2692
3055
 
3056
+ h1,
3057
+ h2,
3058
+ h3,
3059
+ h4,
3060
+ h5,
3061
+ h6 {
3062
+ margin: 0;
3063
+ line-height: 2.5;
3064
+ }
3065
+
3066
+ h1 {
3067
+ font-size: 18px;
3068
+ }
3069
+
3070
+ h2 {
3071
+ font-size: 16px;
3072
+ }
3073
+
3074
+ h3,
3075
+ h4,
3076
+ h5,
3077
+ h6 {
3078
+ font-size: 14px;
3079
+ }
3080
+
2693
3081
  p {
2694
3082
  margin: 0;
2695
3083
  }
@@ -2701,7 +3089,7 @@ var Content = styled7.div`
2701
3089
  table {
2702
3090
  width: 100%;
2703
3091
  border-collapse: collapse;
2704
- margin: 0;
3092
+ margin: 8px 0 0;
2705
3093
  overflow: hidden;
2706
3094
  border-radius: 14px;
2707
3095
  border: 1px solid rgba(255, 255, 255, 0.08);
@@ -2725,6 +3113,10 @@ var Content = styled7.div`
2725
3113
  tbody tr:last-of-type td {
2726
3114
  border-bottom: none;
2727
3115
  }
3116
+ ul,
3117
+ ol {
3118
+ margin: 0 0 8px;
3119
+ }
2728
3120
  `;
2729
3121
  var ContentStack = styled7.div`
2730
3122
  display: flex;
@@ -3003,7 +3395,7 @@ var ChatThreadView = ({
3003
3395
  onQuestionnaireSubmit,
3004
3396
  renderMessageBlock
3005
3397
  }) => {
3006
- const containerRef = useRef4(null);
3398
+ const containerRef = useRef5(null);
3007
3399
  const conversationTurns = useMemo4(
3008
3400
  () => groupConversationTurns(historyMessages, streamingMessage),
3009
3401
  [historyMessages, streamingMessage]
@@ -3011,8 +3403,8 @@ var ChatThreadView = ({
3011
3403
  const latestTurn = conversationTurns[conversationTurns.length - 1];
3012
3404
  const previousTurns = conversationTurns.slice(0, -1);
3013
3405
  const latestUserMessageId = latestTurn?.userMessage?.id;
3014
- const latestUserMessageRef = useRef4(null);
3015
- const reservedSpaceFrameRef = useRef4(null);
3406
+ const latestUserMessageRef = useRef5(null);
3407
+ const reservedSpaceFrameRef = useRef5(null);
3016
3408
  const [latestTurnMinHeight, setLatestTurnMinHeight] = useState4(0);
3017
3409
  const measureLatestTurnMinHeight = useCallback3(() => {
3018
3410
  const container = containerRef.current;
@@ -3300,7 +3692,7 @@ var RetryButton = styled9.button`
3300
3692
  `;
3301
3693
 
3302
3694
  // src/components/chat-composer/index.tsx
3303
- import { useEffect as useEffect6, useLayoutEffect as useLayoutEffect3, useRef as useRef7, useState as useState8 } from "react";
3695
+ import { useEffect as useEffect7, useLayoutEffect as useLayoutEffect3, useRef as useRef8, useState as useState8 } from "react";
3304
3696
  import styled14 from "@emotion/styled";
3305
3697
 
3306
3698
  // src/components/chat-composer/lib/chat-composer.ts
@@ -3412,10 +3804,10 @@ var resolveSendSession = ({
3412
3804
  };
3413
3805
 
3414
3806
  // src/components/chat-composer/hooks/use-chat-composer.ts
3415
- import { useCallback as useCallback4, useEffect as useEffect5, useRef as useRef6, useState as useState6 } from "react";
3807
+ import { useCallback as useCallback4, useEffect as useEffect6, useRef as useRef7, useState as useState6 } from "react";
3416
3808
 
3417
3809
  // src/components/chat-composer/hooks/use-composer-attachments.ts
3418
- import { useEffect as useEffect4, useRef as useRef5, useState as useState5 } from "react";
3810
+ import { useEffect as useEffect5, useRef as useRef6, useState as useState5 } from "react";
3419
3811
  var SUPPORTED_IMAGE_MIME_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/webp"]);
3420
3812
  var MAX_COMPOSER_ATTACHMENTS = 10;
3421
3813
  var createObjectUrl = (file) => typeof URL !== "undefined" && typeof URL.createObjectURL === "function" ? URL.createObjectURL(file) : "";
@@ -3430,11 +3822,11 @@ var releaseComposerAttachments = (attachments) => {
3430
3822
  };
3431
3823
  var useComposerAttachments = () => {
3432
3824
  const [attachments, setAttachments] = useState5([]);
3433
- const attachmentsRef = useRef5([]);
3434
- useEffect4(() => {
3825
+ const attachmentsRef = useRef6([]);
3826
+ useEffect5(() => {
3435
3827
  attachmentsRef.current = attachments;
3436
3828
  }, [attachments]);
3437
- useEffect4(
3829
+ useEffect5(
3438
3830
  () => () => {
3439
3831
  releaseComposerAttachments(attachmentsRef.current);
3440
3832
  },
@@ -3562,7 +3954,7 @@ var useChatComposer = () => {
3562
3954
  setIsModelsLoading(false);
3563
3955
  }
3564
3956
  }, [transport]);
3565
- useEffect5(() => {
3957
+ useEffect6(() => {
3566
3958
  void fetchModels();
3567
3959
  }, [fetchModels]);
3568
3960
  const hasModels = availableModels.length > 0;
@@ -3571,22 +3963,22 @@ var useChatComposer = () => {
3571
3963
  const [selectedMode, setSelectedModeLocal] = useState6(DEFAULT_CHAT_AGENT_MODE);
3572
3964
  const [attachmentNotice, setAttachmentNotice] = useState6(null);
3573
3965
  const { attachments, appendFiles, removeAttachment, takeMessageAttachments } = useComposerAttachments();
3574
- const abortControllerRef = useRef6(null);
3575
- const stopRequestRef = useRef6(null);
3576
- const lastRequestRef = useRef6(null);
3577
- useEffect5(() => {
3966
+ const abortControllerRef = useRef7(null);
3967
+ const stopRequestRef = useRef7(null);
3968
+ const lastRequestRef = useRef7(null);
3969
+ useEffect6(() => {
3578
3970
  setSelectedModel(
3579
3971
  (current) => resolveSelectedChatModel({ currentModel: current, availableModels, isModelsLoading })
3580
3972
  );
3581
3973
  }, [availableModels, isModelsLoading]);
3582
- useEffect5(() => {
3974
+ useEffect6(() => {
3583
3975
  if (activeSession) {
3584
3976
  setSelectedModeLocal(activeSession.mode ?? DEFAULT_CHAT_AGENT_MODE);
3585
3977
  return;
3586
3978
  }
3587
3979
  setSelectedModeLocal(preferredMode ?? DEFAULT_CHAT_AGENT_MODE);
3588
3980
  }, [activeSession, preferredMode]);
3589
- useEffect5(() => {
3981
+ useEffect6(() => {
3590
3982
  if (!attachmentNotice)
3591
3983
  return;
3592
3984
  const timeoutId = window.setTimeout(
@@ -4417,8 +4809,8 @@ var ChatComposerView = ({
4417
4809
  onStop,
4418
4810
  onSend
4419
4811
  }) => {
4420
- const imageInputRef = useRef7(null);
4421
- const inputRef = useRef7(null);
4812
+ const imageInputRef = useRef8(null);
4813
+ const inputRef = useRef8(null);
4422
4814
  const [isComposerExpandable, setIsComposerExpandable] = useState8(false);
4423
4815
  const [isComposerExpanded, setIsComposerExpanded] = useState8(false);
4424
4816
  const canSend = canSendChatMessage({
@@ -4569,7 +4961,7 @@ var ChatComposer = () => {
4569
4961
  const { labels, sendRef, retryRef, enableImageAttachments } = useChatContext();
4570
4962
  const { state, actions } = useChatComposer();
4571
4963
  const { send, retry } = actions;
4572
- useEffect6(() => {
4964
+ useEffect7(() => {
4573
4965
  sendRef.current = send;
4574
4966
  retryRef.current = async () => {
4575
4967
  retry();
@@ -4843,7 +5235,7 @@ var ChatConversationList = () => {
4843
5235
  };
4844
5236
  return /* @__PURE__ */ jsxs12(Container3, { children: [
4845
5237
  /* @__PURE__ */ jsxs12(Toolbar, { children: [
4846
- /* @__PURE__ */ jsx17(Title4, { children: "Sessions" }),
5238
+ /* @__PURE__ */ jsx17(Title3, { children: "Sessions" }),
4847
5239
  /* @__PURE__ */ jsx17(CreateButton, { type: "button", "data-testid": "chat-create-session", onClick: handleCreateSession, children: labels.newChat })
4848
5240
  ] }),
4849
5241
  /* @__PURE__ */ jsx17(List2, { "data-testid": "chat-session-list", children: sessions.map((session) => /* @__PURE__ */ jsx17(
@@ -4872,7 +5264,7 @@ var Toolbar = styled16.div`
4872
5264
  flex-direction: column;
4873
5265
  gap: 12px;
4874
5266
  `;
4875
- var Title4 = styled16.h2`
5267
+ var Title3 = styled16.h2`
4876
5268
  margin: 0;
4877
5269
  font-size: 14px;
4878
5270
  color: var(--text-secondary);