@xinghunm/ai-chat 1.0.2 → 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
@@ -695,7 +698,7 @@ var AiChatProvider = (props) => {
695
698
  };
696
699
 
697
700
  // src/components/chat-thread/index.tsx
698
- 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";
699
702
  import styled9 from "@emotion/styled";
700
703
 
701
704
  // src/context/use-chat-context.ts
@@ -1485,31 +1488,126 @@ var Value = styled3.span`
1485
1488
  `;
1486
1489
 
1487
1490
  // src/components/chat-thread/components/questionnaire-card.tsx
1488
- import { useState as useState2 } from "react";
1491
+ import {
1492
+ useEffect as useEffect3,
1493
+ useRef as useRef3,
1494
+ useState as useState2
1495
+ } from "react";
1489
1496
  import styled4 from "@emotion/styled";
1490
- 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
1491
1500
  var OTHER_OPTION_VALUE = "__other__";
1492
- var DEFAULT_QUESTIONNAIRE_CARD_LABELS = {
1493
- submitting: "Submitting...",
1494
- submitted: "Selection submitted. Waiting for the plan to continue...",
1495
- validationPrefix: "Please complete:",
1496
- submitFailed: "Failed to submit. Please try again."
1497
- };
1498
- var createInitialAnswers = (questionnaire) => ({
1499
- ...questionnaire.answers ?? {}
1500
- });
1501
+ var getQuestionnaireQuestion = (questionnaire) => questionnaire.question;
1501
1502
  var getMultiSelectAnswerValues = (answer) => Array.isArray(answer) ? answer : [];
1502
- 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) => {
1503
1601
  if (typeof answer !== "string") {
1504
1602
  return {
1505
1603
  selectedValue: void 0,
1506
- otherValue: ""
1604
+ otherValue: otherDraft
1507
1605
  };
1508
1606
  }
1509
- const matchesOption = question.options.some((option) => option.value === answer);
1607
+ const matchesOption = answer !== OTHER_OPTION_VALUE && question.options.some((option) => option.value === answer);
1510
1608
  return {
1511
1609
  selectedValue: matchesOption ? answer : question.allowOther ? OTHER_OPTION_VALUE : void 0,
1512
- otherValue: matchesOption ? "" : answer
1610
+ otherValue: otherDraft
1513
1611
  };
1514
1612
  };
1515
1613
  var updateAnswerValue = (current, questionId, value) => ({
@@ -1521,6 +1619,17 @@ var toggleMultiSelectAnswer = (current, questionId, optionValue) => {
1521
1619
  const nextValues = currentValues.includes(optionValue) ? currentValues.filter((value) => value !== optionValue) : [...currentValues, optionValue];
1522
1620
  return updateAnswerValue(current, questionId, nextValues);
1523
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
+ };
1524
1633
  var getTextInputValue = (answer) => typeof answer === "string" ? String(answer) : "";
1525
1634
  var getNumberInputValue = (answer) => typeof answer === "number" || typeof answer === "string" ? String(answer) : "";
1526
1635
  var getOptionChoiceLabel = (index) => {
@@ -1529,20 +1638,49 @@ var getOptionChoiceLabel = (index) => {
1529
1638
  }
1530
1639
  return String(index + 1);
1531
1640
  };
1532
- var isMissingRequiredAnswer = (question, answers) => {
1533
- const answer = answers[question.id];
1641
+ var normalizeQuestionAnswer = (question, answer, otherDraft = "") => {
1642
+ if (answer === void 0) {
1643
+ return void 0;
1644
+ }
1534
1645
  switch (question.kind) {
1535
- case "boolean":
1536
- return typeof answer !== "boolean";
1537
1646
  case "multi_select":
1538
- return !Array.isArray(answer) || answer.length === 0;
1539
- case "number":
1540
- return typeof answer !== "number" || Number.isNaN(answer);
1541
- 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
+ })();
1542
1667
  case "single_select":
1543
- 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;
1544
1682
  default:
1545
- return true;
1683
+ return answer;
1546
1684
  }
1547
1685
  };
1548
1686
  var formatQuestionAnswer = (question, answer) => {
@@ -1570,80 +1708,221 @@ var formatQuestionAnswer = (question, answer) => {
1570
1708
  return String(answer);
1571
1709
  }
1572
1710
  };
1573
- var normalizeQuestionAnswer = (question, answer) => {
1711
+ var buildQuestionSubmissionDetail = (question, answer) => {
1574
1712
  if (answer === void 0) {
1575
1713
  return void 0;
1576
1714
  }
1577
1715
  switch (question.kind) {
1578
- case "multi_select":
1579
- return Array.isArray(answer) && answer.length > 0 ? answer : void 0;
1580
- case "single_select":
1581
- case "text":
1582
- return typeof answer === "string" && answer.trim() !== "" ? answer : void 0;
1583
- case "number":
1584
- return typeof answer === "number" && !Number.isNaN(answer) ? answer : void 0;
1585
- case "boolean":
1586
- 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
+ }
1587
1749
  default:
1588
- return answer;
1750
+ return {
1751
+ questionId: question.id,
1752
+ kind: question.kind,
1753
+ value: answer
1754
+ };
1589
1755
  }
1590
1756
  };
1757
+ var getMissingRequiredQuestions = (questionnaire, answers, otherDrafts) => {
1758
+ const question = getQuestionnaireQuestion(questionnaire);
1759
+ if (!question || !question.required) {
1760
+ return [];
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();
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
+ );
1591
1859
  var QuestionnaireCardInner = ({
1592
1860
  questionnaire,
1593
1861
  interactive = false,
1594
1862
  onSubmit,
1595
1863
  labels
1596
1864
  }) => {
1865
+ const questionnaireRef = useRef3(questionnaire);
1866
+ const otherInputRefs = useRef3({});
1597
1867
  const [answers, setAnswers] = useState2(
1598
1868
  () => createInitialAnswers(questionnaire)
1599
1869
  );
1870
+ const [otherDrafts, setOtherDrafts] = useState2(
1871
+ () => createInitialOtherDrafts(questionnaire)
1872
+ );
1600
1873
  const [errorMessage, setErrorMessage] = useState2(null);
1601
1874
  const [isSubmitting, setIsSubmitting] = useState2(false);
1602
1875
  const [isSubmitted, setIsSubmitted] = useState2(false);
1876
+ const [pendingFocusQuestionId, setPendingFocusQuestionId] = useState2(null);
1603
1877
  const resolvedLabels = {
1604
1878
  ...DEFAULT_QUESTIONNAIRE_CARD_LABELS,
1605
1879
  ...labels
1606
1880
  };
1607
1881
  const hasExternalFailureStatus = questionnaire.status === "expired" || questionnaire.status === "failed";
1882
+ const question = getQuestionnaireQuestion(questionnaire);
1608
1883
  const visibleErrorMessage = questionnaire.statusMessage ?? errorMessage;
1609
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]);
1610
1901
  const handleSubmit = async () => {
1611
1902
  if (isSubmitting || isSubmitted) {
1612
1903
  return;
1613
1904
  }
1614
- const missingQuestions = questionnaire.questions.filter(
1615
- (question) => question.required && isMissingRequiredAnswer(question, answers)
1616
- );
1905
+ const missingQuestions = getMissingRequiredQuestions(questionnaire, answers, otherDrafts);
1617
1906
  if (missingQuestions.length > 0) {
1618
1907
  setErrorMessage(
1619
- `${resolvedLabels.validationPrefix} ${missingQuestions.map((question) => question.label).join(", ")}`
1908
+ `${resolvedLabels.validationPrefix} ${missingQuestions.map((question2) => question2.label).join(", ")}`
1620
1909
  );
1621
1910
  return;
1622
1911
  }
1623
1912
  setErrorMessage(null);
1624
1913
  setIsSubmitting(true);
1625
- const normalizedAnswers = Object.fromEntries(
1626
- questionnaire.questions.flatMap((question) => {
1627
- const value = normalizeQuestionAnswer(question, answers[question.id]);
1628
- return value === void 0 ? [] : [[question.id, value]];
1629
- })
1914
+ const { normalizedAnswers, submissionDetails, content } = prepareQuestionnaireSubmission(
1915
+ questionnaire,
1916
+ answers,
1917
+ otherDrafts
1630
1918
  );
1631
- const contentLines = [
1632
- questionnaire.title ?? "Questionnaire responses",
1633
- ...questionnaire.questions.flatMap((question) => {
1634
- const value = normalizedAnswers[question.id];
1635
- if (value === void 0) {
1636
- return [];
1637
- }
1638
- return [`- ${question.label}: ${formatQuestionAnswer(question, value)}`];
1639
- })
1640
- ];
1641
1919
  try {
1642
1920
  await onSubmit?.({
1643
1921
  questionnaireId: questionnaire.questionnaireId,
1644
1922
  ...questionnaire.blockKey ? { blockKey: questionnaire.blockKey } : {},
1645
1923
  answers: normalizedAnswers,
1646
- content: contentLines.join("\n")
1924
+ details: submissionDetails,
1925
+ content
1647
1926
  });
1648
1927
  setIsSubmitted(true);
1649
1928
  } catch (error) {
@@ -1652,125 +1931,156 @@ var QuestionnaireCardInner = ({
1652
1931
  setIsSubmitting(false);
1653
1932
  }
1654
1933
  };
1655
- const renderQuestion = (question) => {
1656
- const renderOptionChoice = ({
1657
- questionId,
1658
- optionLabel,
1659
- index,
1660
- isSelected,
1661
- onClick,
1662
- inlineInput,
1663
- tone = "default"
1664
- }) => /* @__PURE__ */ jsxs3(
1665
- OptionChoiceItem,
1666
- {
1667
- role: "button",
1668
- tabIndex: isInteractionLocked ? -1 : 0,
1669
- "aria-pressed": isSelected,
1670
- "data-selected": isSelected,
1671
- "data-tone": tone,
1672
- "data-testid": `question-option-${questionId}-${index}`,
1673
- onClick: (event) => {
1674
- if (isInteractionLocked) {
1675
- return;
1676
- }
1677
- if (event.target instanceof HTMLElement && event.target.closest("input")) {
1678
- return;
1679
- }
1680
- onClick();
1681
- },
1682
- onKeyDown: (event) => {
1683
- if (isInteractionLocked) {
1684
- return;
1685
- }
1686
- if (event.key !== "Enter" && event.key !== " ") {
1687
- return;
1688
- }
1689
- event.preventDefault();
1690
- onClick();
1691
- },
1692
- children: [
1693
- /* @__PURE__ */ jsx5(OptionChoiceMarker, { "data-selected": isSelected, children: getOptionChoiceLabel(index) }),
1694
- /* @__PURE__ */ jsxs3(OptionChoiceContent, { children: [
1695
- inlineInput ? null : /* @__PURE__ */ jsx5(OptionChoiceLabel, { children: optionLabel }),
1696
- inlineInput
1697
- ] })
1698
- ]
1699
- },
1700
- `${questionId}-${optionLabel}`
1701
- );
1702
- switch (question.kind) {
1703
- case "multi_select":
1704
- return /* @__PURE__ */ jsx5(QuestionBody, { children: /* @__PURE__ */ jsx5(OptionList, { children: question.options.map((option, index) => {
1705
- const selectedValues = getMultiSelectAnswerValues(answers[question.id]);
1706
- const isSelected = selectedValues.includes(option.value);
1707
- return renderOptionChoice({
1708
- questionId: question.id,
1709
- optionLabel: option.label,
1710
- index,
1711
- isSelected,
1712
- onClick: () => setAnswers(
1713
- (current) => toggleMultiSelectAnswer(current, question.id, option.value)
1714
- )
1715
- });
1716
- }) }) });
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
+ }
1717
2004
  case "single_select": {
1718
- const singleSelectDraft = getSingleSelectDraftState(question, answers[question.id]);
2005
+ const singleSelectDraft = getSingleSelectDraftState(
2006
+ questionToRender,
2007
+ answers[questionToRender.id],
2008
+ otherDrafts[questionToRender.id] ?? ""
2009
+ );
1719
2010
  return /* @__PURE__ */ jsx5(QuestionBody, { children: /* @__PURE__ */ jsxs3(OptionList, { children: [
1720
- question.options.map((option, index) => {
2011
+ questionToRender.options.map((option, index) => {
1721
2012
  const isSelected = singleSelectDraft.selectedValue === option.value;
1722
- return renderOptionChoice({
1723
- questionId: question.id,
1724
- optionLabel: option.label,
1725
- index,
1726
- isSelected,
1727
- onClick: () => setAnswers((current) => updateAnswerValue(current, question.id, option.value))
1728
- });
1729
- }),
1730
- question.allowOther ? renderOptionChoice({
1731
- questionId: question.id,
1732
- optionLabel: "Other",
1733
- index: question.options.length,
1734
- isSelected: singleSelectDraft.selectedValue === OTHER_OPTION_VALUE,
1735
- tone: "other",
1736
- onClick: () => setAnswers(
1737
- (current) => updateAnswerValue(current, question.id, singleSelectDraft.otherValue)
1738
- ),
1739
- inlineInput: singleSelectDraft.selectedValue === OTHER_OPTION_VALUE ? /* @__PURE__ */ jsx5(
1740
- InlineOtherInput,
2013
+ return /* @__PURE__ */ jsx5(
2014
+ OptionChoice,
1741
2015
  {
1742
- "data-testid": `question-input-${question.id}`,
1743
- type: "text",
1744
- value: singleSelectDraft.otherValue,
1745
- placeholder: "Other",
1746
- readOnly: isInteractionLocked,
1747
- onClick: (event) => {
1748
- event.stopPropagation();
1749
- },
1750
- onKeyDown: (event) => {
1751
- event.stopPropagation();
1752
- },
1753
- onChange: (event) => {
1754
- setAnswers(
1755
- (current) => updateAnswerValue(current, question.id, event.target.value)
1756
- );
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);
1757
2040
  }
1758
- }
1759
- ) : null
1760
- }) : 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
1761
2069
  ] }) });
1762
2070
  }
1763
2071
  case "text":
1764
2072
  return /* @__PURE__ */ jsx5(QuestionBody, { children: /* @__PURE__ */ jsx5(
1765
2073
  TextInput,
1766
2074
  {
1767
- "data-testid": `question-input-${question.id}`,
2075
+ "data-testid": `question-input-${questionToRender.id}`,
1768
2076
  type: "text",
1769
- value: getTextInputValue(answers[question.id]),
1770
- placeholder: question.placeholder,
2077
+ value: getTextInputValue(answers[questionToRender.id]),
2078
+ placeholder: questionToRender.placeholder,
1771
2079
  readOnly: isInteractionLocked,
1772
2080
  onChange: (event) => {
1773
- setAnswers((current) => updateAnswerValue(current, question.id, event.target.value));
2081
+ setAnswers(
2082
+ (current) => updateAnswerValue(current, questionToRender.id, event.target.value)
2083
+ );
1774
2084
  }
1775
2085
  }
1776
2086
  ) });
@@ -1779,55 +2089,63 @@ var QuestionnaireCardInner = ({
1779
2089
  /* @__PURE__ */ jsx5(
1780
2090
  TextInput,
1781
2091
  {
1782
- "data-testid": `question-input-${question.id}`,
2092
+ "data-testid": `question-input-${questionToRender.id}`,
1783
2093
  type: "number",
1784
- value: getNumberInputValue(answers[question.id]),
1785
- placeholder: question.placeholder,
2094
+ value: getNumberInputValue(answers[questionToRender.id]),
2095
+ placeholder: questionToRender.placeholder,
1786
2096
  readOnly: isInteractionLocked,
1787
2097
  onChange: (event) => {
1788
2098
  setAnswers(
1789
2099
  (current) => updateAnswerValue(
1790
2100
  current,
1791
- question.id,
2101
+ questionToRender.id,
1792
2102
  event.target.value === "" ? void 0 : Number(event.target.value)
1793
2103
  )
1794
2104
  );
1795
2105
  }
1796
2106
  }
1797
2107
  ),
1798
- question.unit ? /* @__PURE__ */ jsx5(Unit, { children: question.unit }) : null
2108
+ questionToRender.unit ? /* @__PURE__ */ jsx5(Unit, { children: questionToRender.unit }) : null
1799
2109
  ] }) });
1800
2110
  case "boolean":
1801
2111
  return /* @__PURE__ */ jsx5(QuestionBody, { children: /* @__PURE__ */ jsxs3(OptionList, { children: [
1802
- renderOptionChoice({
1803
- questionId: question.id,
1804
- optionLabel: question.trueLabel ?? "Yes",
1805
- index: 0,
1806
- isSelected: answers[question.id] === true,
1807
- onClick: () => setAnswers((current) => updateAnswerValue(current, question.id, true))
1808
- }),
1809
- renderOptionChoice({
1810
- questionId: question.id,
1811
- optionLabel: question.falseLabel ?? "No",
1812
- index: 1,
1813
- isSelected: answers[question.id] === false,
1814
- onClick: () => setAnswers((current) => updateAnswerValue(current, question.id, false))
1815
- })
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
+ )
1816
2134
  ] }) });
1817
2135
  default:
1818
2136
  return null;
1819
2137
  }
1820
2138
  };
1821
2139
  return /* @__PURE__ */ jsxs3(Card4, { "data-testid": "questionnaire-card", children: [
1822
- questionnaire.title ? /* @__PURE__ */ jsx5(Title3, { children: questionnaire.title }) : null,
1823
2140
  questionnaire.description ? /* @__PURE__ */ jsx5(Description, { children: questionnaire.description }) : null,
1824
- /* @__PURE__ */ jsx5(QuestionList, { children: questionnaire.questions.map((question) => /* @__PURE__ */ jsxs3(QuestionCard, { children: [
2141
+ /* @__PURE__ */ jsx5(QuestionList, { children: /* @__PURE__ */ jsxs3(QuestionCard, { children: [
1825
2142
  /* @__PURE__ */ jsxs3(QuestionLabel, { children: [
1826
2143
  question.label,
1827
2144
  question.required ? /* @__PURE__ */ jsx5(Required, { children: "*" }) : null
1828
2145
  ] }),
2146
+ question.kind === "multi_select" ? /* @__PURE__ */ jsx5(QuestionHint, { children: resolvedLabels.multiSelectHint }) : null,
1829
2147
  renderQuestion(question)
1830
- ] }, question.id)) }),
2148
+ ] }, question.id) }),
1831
2149
  visibleErrorMessage ? /* @__PURE__ */ jsx5(ErrorMessage, { "data-testid": "questionnaire-error", children: visibleErrorMessage }) : null,
1832
2150
  isSubmitted ? /* @__PURE__ */ jsx5(SuccessMessage, { "data-testid": "questionnaire-success", children: resolvedLabels.submitted }) : interactive && !hasExternalFailureStatus ? /* @__PURE__ */ jsx5(
1833
2151
  SubmitButton,
@@ -1843,12 +2161,6 @@ var QuestionnaireCardInner = ({
1843
2161
  ) : null
1844
2162
  ] });
1845
2163
  };
1846
- var getQuestionnaireStateKey = (questionnaire) => JSON.stringify([
1847
- questionnaire.questionnaireId,
1848
- questionnaire.questions,
1849
- questionnaire.status,
1850
- questionnaire.statusMessage
1851
- ]);
1852
2164
  var QuestionnaireCard = (props) => /* @__PURE__ */ jsx5(QuestionnaireCardInner, { ...props }, getQuestionnaireStateKey(props.questionnaire));
1853
2165
  var Card4 = styled4.section`
1854
2166
  display: grid;
@@ -1858,11 +2170,6 @@ var Card4 = styled4.section`
1858
2170
  border: 1px solid rgba(255, 255, 255, 0.08);
1859
2171
  background: rgba(255, 255, 255, 0.03);
1860
2172
  `;
1861
- var Title3 = styled4.strong`
1862
- color: rgba(255, 255, 255, 0.94);
1863
- font-size: 16px;
1864
- line-height: 1.4;
1865
- `;
1866
2173
  var Description = styled4.p`
1867
2174
  margin: 0;
1868
2175
  color: rgba(255, 255, 255, 0.72);
@@ -1881,13 +2188,18 @@ var QuestionCard = styled4.div`
1881
2188
  `;
1882
2189
  var QuestionLabel = styled4.div`
1883
2190
  color: rgba(255, 255, 255, 0.9);
1884
- font-size: 13px;
2191
+ font-size: 14px;
1885
2192
  font-weight: 600;
1886
2193
  `;
1887
2194
  var Required = styled4.span`
1888
2195
  margin-left: 4px;
1889
2196
  color: rgba(255, 122, 122, 0.9);
1890
2197
  `;
2198
+ var QuestionHint = styled4.div`
2199
+ color: rgba(132, 180, 255, 0.9);
2200
+ font-size: 12px;
2201
+ line-height: 1.4;
2202
+ `;
1891
2203
  var QuestionBody = styled4.div`
1892
2204
  display: grid;
1893
2205
  gap: 10px;
@@ -1905,7 +2217,7 @@ var OptionChoiceItem = styled4.div`
1905
2217
  border: 1px solid rgba(255, 255, 255, 0.1);
1906
2218
  border-radius: 14px;
1907
2219
  background: rgba(255, 255, 255, 0.03);
1908
- padding: 12px 14px;
2220
+ padding: 2px 12px;
1909
2221
  color: rgba(255, 255, 255, 0.9);
1910
2222
  cursor: pointer;
1911
2223
  transition:
@@ -1956,8 +2268,11 @@ var OptionChoiceMarker = styled4.span`
1956
2268
  }
1957
2269
  `;
1958
2270
  var OptionChoiceContent = styled4.span`
1959
- display: grid;
1960
- gap: 2px;
2271
+ display: flex;
2272
+ flex-direction: column;
2273
+ justify-content: center;
2274
+ gap: 4px;
2275
+ min-height: 40px;
1961
2276
  min-width: 0;
1962
2277
  flex: 1;
1963
2278
  `;
@@ -1980,8 +2295,37 @@ var TextInput = styled4.input`
1980
2295
  color: rgba(255, 255, 255, 0.34);
1981
2296
  }
1982
2297
  `;
1983
- var InlineOtherInput = styled4(TextInput)`
2298
+ var InlineOtherInput = styled4(InputField)`
2299
+ width: 100%;
1984
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
+ }
1985
2329
  `;
1986
2330
  var NumberInputRow = styled4.div`
1987
2331
  display: flex;
@@ -2067,7 +2411,7 @@ var Detail = styled5.li`
2067
2411
 
2068
2412
  // src/components/chat-thread/components/image-viewer.tsx
2069
2413
  import styled6 from "@emotion/styled";
2070
- import { useEffect as useEffect3, useRef as useRef3 } from "react";
2414
+ import { useEffect as useEffect4, useRef as useRef4 } from "react";
2071
2415
  import { jsx as jsx7 } from "@emotion/react/jsx-runtime";
2072
2416
  var Overlay = styled6.div`
2073
2417
  position: fixed;
@@ -2086,8 +2430,8 @@ var Img = styled6.img`
2086
2430
  border-radius: 4px;
2087
2431
  `;
2088
2432
  var ImageViewer = ({ src, alt, onClose }) => {
2089
- const overlayRef = useRef3(null);
2090
- useEffect3(() => {
2433
+ const overlayRef = useRef4(null);
2434
+ useEffect4(() => {
2091
2435
  const handleKey = (e) => {
2092
2436
  if (e.key === "Escape")
2093
2437
  onClose();
@@ -2095,7 +2439,7 @@ var ImageViewer = ({ src, alt, onClose }) => {
2095
2439
  document.addEventListener("keydown", handleKey);
2096
2440
  return () => document.removeEventListener("keydown", handleKey);
2097
2441
  }, [onClose]);
2098
- useEffect3(() => {
2442
+ useEffect4(() => {
2099
2443
  overlayRef.current?.focus();
2100
2444
  }, []);
2101
2445
  const stopPropagation = (e) => e.stopPropagation();
@@ -2290,9 +2634,7 @@ var arePlanQuestionsEqual = (previousQuestion, nextQuestion) => {
2290
2634
  return false;
2291
2635
  }
2292
2636
  };
2293
- 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(
2294
- (question, index) => arePlanQuestionsEqual(question, nextQuestionnaire.questions[index])
2295
- ) && 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);
2296
2638
  var areMessageBlocksEqual = (previousBlocks, nextBlocks) => {
2297
2639
  if (previousBlocks === nextBlocks) {
2298
2640
  return true;
@@ -2446,7 +2788,10 @@ var ChatMessageItemView = ({
2446
2788
  submitting: labels.questionnaireSubmitting,
2447
2789
  submitted: labels.questionnaireSubmitted,
2448
2790
  validationPrefix: labels.questionnaireValidationPrefix,
2449
- submitFailed: labels.questionnaireSubmitFailed
2791
+ submitFailed: labels.questionnaireSubmitFailed,
2792
+ multiSelectHint: labels.questionnaireMultiSelectHint,
2793
+ otherOptionLabel: labels.questionnaireOtherOptionLabel,
2794
+ otherPlaceholder: labels.questionnaireOtherPlaceholder
2450
2795
  },
2451
2796
  onSubmit: canSubmitQuestionnaire ? (submission) => onQuestionnaireSubmit({
2452
2797
  ...submission,
@@ -2705,8 +3050,34 @@ var CollapseToggle = styled7.button`
2705
3050
  `;
2706
3051
  var Content = styled7.div`
2707
3052
  color: rgba(255, 255, 255, 0.92);
3053
+ font-size: 14px;
2708
3054
  line-height: 1.6;
2709
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
+
2710
3081
  p {
2711
3082
  margin: 0;
2712
3083
  }
@@ -2718,7 +3089,7 @@ var Content = styled7.div`
2718
3089
  table {
2719
3090
  width: 100%;
2720
3091
  border-collapse: collapse;
2721
- margin: 0;
3092
+ margin: 8px 0 0;
2722
3093
  overflow: hidden;
2723
3094
  border-radius: 14px;
2724
3095
  border: 1px solid rgba(255, 255, 255, 0.08);
@@ -2742,6 +3113,10 @@ var Content = styled7.div`
2742
3113
  tbody tr:last-of-type td {
2743
3114
  border-bottom: none;
2744
3115
  }
3116
+ ul,
3117
+ ol {
3118
+ margin: 0 0 8px;
3119
+ }
2745
3120
  `;
2746
3121
  var ContentStack = styled7.div`
2747
3122
  display: flex;
@@ -3020,7 +3395,7 @@ var ChatThreadView = ({
3020
3395
  onQuestionnaireSubmit,
3021
3396
  renderMessageBlock
3022
3397
  }) => {
3023
- const containerRef = useRef4(null);
3398
+ const containerRef = useRef5(null);
3024
3399
  const conversationTurns = useMemo4(
3025
3400
  () => groupConversationTurns(historyMessages, streamingMessage),
3026
3401
  [historyMessages, streamingMessage]
@@ -3028,8 +3403,8 @@ var ChatThreadView = ({
3028
3403
  const latestTurn = conversationTurns[conversationTurns.length - 1];
3029
3404
  const previousTurns = conversationTurns.slice(0, -1);
3030
3405
  const latestUserMessageId = latestTurn?.userMessage?.id;
3031
- const latestUserMessageRef = useRef4(null);
3032
- const reservedSpaceFrameRef = useRef4(null);
3406
+ const latestUserMessageRef = useRef5(null);
3407
+ const reservedSpaceFrameRef = useRef5(null);
3033
3408
  const [latestTurnMinHeight, setLatestTurnMinHeight] = useState4(0);
3034
3409
  const measureLatestTurnMinHeight = useCallback3(() => {
3035
3410
  const container = containerRef.current;
@@ -3317,7 +3692,7 @@ var RetryButton = styled9.button`
3317
3692
  `;
3318
3693
 
3319
3694
  // src/components/chat-composer/index.tsx
3320
- 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";
3321
3696
  import styled14 from "@emotion/styled";
3322
3697
 
3323
3698
  // src/components/chat-composer/lib/chat-composer.ts
@@ -3429,10 +3804,10 @@ var resolveSendSession = ({
3429
3804
  };
3430
3805
 
3431
3806
  // src/components/chat-composer/hooks/use-chat-composer.ts
3432
- 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";
3433
3808
 
3434
3809
  // src/components/chat-composer/hooks/use-composer-attachments.ts
3435
- 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";
3436
3811
  var SUPPORTED_IMAGE_MIME_TYPES = /* @__PURE__ */ new Set(["image/png", "image/jpeg", "image/webp"]);
3437
3812
  var MAX_COMPOSER_ATTACHMENTS = 10;
3438
3813
  var createObjectUrl = (file) => typeof URL !== "undefined" && typeof URL.createObjectURL === "function" ? URL.createObjectURL(file) : "";
@@ -3447,11 +3822,11 @@ var releaseComposerAttachments = (attachments) => {
3447
3822
  };
3448
3823
  var useComposerAttachments = () => {
3449
3824
  const [attachments, setAttachments] = useState5([]);
3450
- const attachmentsRef = useRef5([]);
3451
- useEffect4(() => {
3825
+ const attachmentsRef = useRef6([]);
3826
+ useEffect5(() => {
3452
3827
  attachmentsRef.current = attachments;
3453
3828
  }, [attachments]);
3454
- useEffect4(
3829
+ useEffect5(
3455
3830
  () => () => {
3456
3831
  releaseComposerAttachments(attachmentsRef.current);
3457
3832
  },
@@ -3579,7 +3954,7 @@ var useChatComposer = () => {
3579
3954
  setIsModelsLoading(false);
3580
3955
  }
3581
3956
  }, [transport]);
3582
- useEffect5(() => {
3957
+ useEffect6(() => {
3583
3958
  void fetchModels();
3584
3959
  }, [fetchModels]);
3585
3960
  const hasModels = availableModels.length > 0;
@@ -3588,22 +3963,22 @@ var useChatComposer = () => {
3588
3963
  const [selectedMode, setSelectedModeLocal] = useState6(DEFAULT_CHAT_AGENT_MODE);
3589
3964
  const [attachmentNotice, setAttachmentNotice] = useState6(null);
3590
3965
  const { attachments, appendFiles, removeAttachment, takeMessageAttachments } = useComposerAttachments();
3591
- const abortControllerRef = useRef6(null);
3592
- const stopRequestRef = useRef6(null);
3593
- const lastRequestRef = useRef6(null);
3594
- useEffect5(() => {
3966
+ const abortControllerRef = useRef7(null);
3967
+ const stopRequestRef = useRef7(null);
3968
+ const lastRequestRef = useRef7(null);
3969
+ useEffect6(() => {
3595
3970
  setSelectedModel(
3596
3971
  (current) => resolveSelectedChatModel({ currentModel: current, availableModels, isModelsLoading })
3597
3972
  );
3598
3973
  }, [availableModels, isModelsLoading]);
3599
- useEffect5(() => {
3974
+ useEffect6(() => {
3600
3975
  if (activeSession) {
3601
3976
  setSelectedModeLocal(activeSession.mode ?? DEFAULT_CHAT_AGENT_MODE);
3602
3977
  return;
3603
3978
  }
3604
3979
  setSelectedModeLocal(preferredMode ?? DEFAULT_CHAT_AGENT_MODE);
3605
3980
  }, [activeSession, preferredMode]);
3606
- useEffect5(() => {
3981
+ useEffect6(() => {
3607
3982
  if (!attachmentNotice)
3608
3983
  return;
3609
3984
  const timeoutId = window.setTimeout(
@@ -4434,8 +4809,8 @@ var ChatComposerView = ({
4434
4809
  onStop,
4435
4810
  onSend
4436
4811
  }) => {
4437
- const imageInputRef = useRef7(null);
4438
- const inputRef = useRef7(null);
4812
+ const imageInputRef = useRef8(null);
4813
+ const inputRef = useRef8(null);
4439
4814
  const [isComposerExpandable, setIsComposerExpandable] = useState8(false);
4440
4815
  const [isComposerExpanded, setIsComposerExpanded] = useState8(false);
4441
4816
  const canSend = canSendChatMessage({
@@ -4586,7 +4961,7 @@ var ChatComposer = () => {
4586
4961
  const { labels, sendRef, retryRef, enableImageAttachments } = useChatContext();
4587
4962
  const { state, actions } = useChatComposer();
4588
4963
  const { send, retry } = actions;
4589
- useEffect6(() => {
4964
+ useEffect7(() => {
4590
4965
  sendRef.current = send;
4591
4966
  retryRef.current = async () => {
4592
4967
  retry();
@@ -4860,7 +5235,7 @@ var ChatConversationList = () => {
4860
5235
  };
4861
5236
  return /* @__PURE__ */ jsxs12(Container3, { children: [
4862
5237
  /* @__PURE__ */ jsxs12(Toolbar, { children: [
4863
- /* @__PURE__ */ jsx17(Title4, { children: "Sessions" }),
5238
+ /* @__PURE__ */ jsx17(Title3, { children: "Sessions" }),
4864
5239
  /* @__PURE__ */ jsx17(CreateButton, { type: "button", "data-testid": "chat-create-session", onClick: handleCreateSession, children: labels.newChat })
4865
5240
  ] }),
4866
5241
  /* @__PURE__ */ jsx17(List2, { "data-testid": "chat-session-list", children: sessions.map((session) => /* @__PURE__ */ jsx17(
@@ -4889,7 +5264,7 @@ var Toolbar = styled16.div`
4889
5264
  flex-direction: column;
4890
5265
  gap: 12px;
4891
5266
  `;
4892
- var Title4 = styled16.h2`
5267
+ var Title3 = styled16.h2`
4893
5268
  margin: 0;
4894
5269
  font-size: 14px;
4895
5270
  color: var(--text-secondary);