@iota-uz/sdk 0.3.4 → 0.4.7

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.
Files changed (65) hide show
  1. package/dist/applet/core.cjs +251 -0
  2. package/dist/applet/core.cjs.map +1 -0
  3. package/dist/applet/core.d.cts +172 -0
  4. package/dist/applet/core.d.ts +172 -0
  5. package/dist/applet/core.mjs +237 -0
  6. package/dist/applet/core.mjs.map +1 -0
  7. package/dist/applet/devtools.cjs +131 -0
  8. package/dist/applet/devtools.cjs.map +1 -0
  9. package/dist/applet/devtools.d.cts +7 -0
  10. package/dist/applet/devtools.d.ts +7 -0
  11. package/dist/applet/devtools.mjs +128 -0
  12. package/dist/applet/devtools.mjs.map +1 -0
  13. package/dist/applet/host.cjs +256 -0
  14. package/dist/applet/host.cjs.map +1 -0
  15. package/dist/applet/host.d.cts +62 -0
  16. package/dist/applet/host.d.ts +62 -0
  17. package/dist/applet/host.mjs +251 -0
  18. package/dist/applet/host.mjs.map +1 -0
  19. package/dist/bichat/index.cjs +352 -409
  20. package/dist/bichat/index.cjs.map +1 -1
  21. package/dist/bichat/index.d.cts +8 -116
  22. package/dist/bichat/index.d.ts +8 -116
  23. package/dist/bichat/index.mjs +354 -403
  24. package/dist/bichat/index.mjs.map +1 -1
  25. package/dist/fonts/Actay/Actay-Regular.otf +0 -0
  26. package/dist/fonts/Actay/Actay-RegularItalic.otf +0 -0
  27. package/dist/fonts/Actay/ActayCondensed-Thin.otf +0 -0
  28. package/dist/fonts/Actay/ActayCondensed-ThinItalic.otf +0 -0
  29. package/dist/fonts/Actay/ActayWide-Bold.otf +0 -0
  30. package/dist/fonts/Actay/ActayWide-BoldItalic.otf +0 -0
  31. package/dist/fonts/Gilroy/Gilroy-Black.woff2 +0 -0
  32. package/dist/fonts/Gilroy/Gilroy-BlackItalic.woff2 +0 -0
  33. package/dist/fonts/Gilroy/Gilroy-Bold.woff2 +0 -0
  34. package/dist/fonts/Gilroy/Gilroy-BoldItalic.woff2 +0 -0
  35. package/dist/fonts/Gilroy/Gilroy-Extrabold.woff2 +0 -0
  36. package/dist/fonts/Gilroy/Gilroy-ExtraboldItalic.woff2 +0 -0
  37. package/dist/fonts/Gilroy/Gilroy-Heavy.woff2 +0 -0
  38. package/dist/fonts/Gilroy/Gilroy-HeavyItalic.woff2 +0 -0
  39. package/dist/fonts/Gilroy/Gilroy-Light.woff2 +0 -0
  40. package/dist/fonts/Gilroy/Gilroy-LightItalic.woff2 +0 -0
  41. package/dist/fonts/Gilroy/Gilroy-Medium.woff2 +0 -0
  42. package/dist/fonts/Gilroy/Gilroy-MediumItalic.woff2 +0 -0
  43. package/dist/fonts/Gilroy/Gilroy-Regular.woff2 +0 -0
  44. package/dist/fonts/Gilroy/Gilroy-RegularItalic.woff2 +0 -0
  45. package/dist/fonts/Gilroy/Gilroy-Semibold.woff2 +0 -0
  46. package/dist/fonts/Gilroy/Gilroy-SemiboldItalic.woff2 +0 -0
  47. package/dist/fonts/Gilroy/Gilroy-Thin.woff2 +0 -0
  48. package/dist/fonts/Gilroy/Gilroy-ThinItalic.woff2 +0 -0
  49. package/dist/fonts/Gilroy/Gilroy-UltraLight.woff2 +0 -0
  50. package/dist/fonts/Gilroy/Gilroy-UltraLightItalic.woff2 +0 -0
  51. package/dist/fonts/Inter.var.woff2 +0 -0
  52. package/dist/{index-B73-BCi-.d.cts → index-Cs_xWkhC.d.cts} +1 -1
  53. package/dist/{index-B73-BCi-.d.ts → index-Cs_xWkhC.d.ts} +1 -1
  54. package/dist/index.cjs +52 -4
  55. package/dist/index.cjs.map +1 -1
  56. package/dist/index.d.cts +6 -232
  57. package/dist/index.d.ts +6 -232
  58. package/dist/index.mjs +52 -4
  59. package/dist/index.mjs.map +1 -1
  60. package/package.json +44 -13
  61. package/tailwind/compiled.css +1 -1
  62. package/tailwind/create-config.cjs +16 -135
  63. package/tailwind/sdk-theme.cjs +99 -0
  64. package/LICENSE +0 -201
  65. package/README.MD +0 -166
@@ -95,7 +95,7 @@ function ChartCard({ chartData }) {
95
95
  title,
96
96
  ": "
97
97
  ] }),
98
- t("chart.noData")
98
+ t("Chart.NoData")
99
99
  ] }) });
100
100
  }
101
101
  const apexSeries = chartType === "pie" || chartType === "donut" ? series[0]?.data ?? [] : series.map((s) => ({ name: s.name, data: s.data }));
@@ -171,10 +171,10 @@ function ChartCard({ chartData }) {
171
171
  onClick: handleExportPNG,
172
172
  disabled: isExporting,
173
173
  className: "inline-flex items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs font-medium text-gray-400 opacity-0 transition-all duration-150 hover:bg-gray-100 hover:text-gray-600 focus-visible:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 group-hover/chart:opacity-100 disabled:opacity-50 dark:text-gray-500 dark:hover:bg-gray-700 dark:hover:text-gray-300",
174
- title: t("chart.download"),
175
- children: isExporting ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-500 dark:text-gray-400", children: t("chart.exporting") }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
174
+ title: t("Chart.Download"),
175
+ children: isExporting ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-gray-500 dark:text-gray-400", children: t("Chart.Exporting") }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
176
176
  /* @__PURE__ */ jsxRuntime.jsx(react.DownloadSimple, { className: "h-3.5 w-3.5", weight: "bold" }),
177
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("chart.downloadPNG") })
177
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("Chart.DownloadPNG") })
178
178
  ] })
179
179
  }
180
180
  ) })
@@ -662,15 +662,6 @@ var init_MarkdownRenderer = __esm({
662
662
  }
663
663
  });
664
664
 
665
- // ui/src/bichat/types/index.ts
666
- var MessageRole = /* @__PURE__ */ ((MessageRole2) => {
667
- MessageRole2["User"] = "user";
668
- MessageRole2["Assistant"] = "assistant";
669
- MessageRole2["System"] = "system";
670
- MessageRole2["Tool"] = "tool";
671
- return MessageRole2;
672
- })(MessageRole || {});
673
-
674
665
  // ui/src/bichat/utils/RateLimiter.ts
675
666
  var RateLimiter = class {
676
667
  constructor(config) {
@@ -804,13 +795,17 @@ function loadQueue(sessionId) {
804
795
 
805
796
  // ui/src/bichat/context/ChatContext.tsx
806
797
  init_IotaContext();
807
- var SessionCtx = React.createContext(null);
808
- var MessagingCtx = React.createContext(null);
809
- var InputCtx = React.createContext(null);
810
- var DEFAULT_RATE_LIMIT_CONFIG = {
811
- maxRequests: 20,
812
- windowMs: 6e4
813
- };
798
+
799
+ // ui/src/bichat/types/index.ts
800
+ var MessageRole = /* @__PURE__ */ ((MessageRole2) => {
801
+ MessageRole2["User"] = "user";
802
+ MessageRole2["Assistant"] = "assistant";
803
+ MessageRole2["System"] = "system";
804
+ MessageRole2["Tool"] = "tool";
805
+ return MessageRole2;
806
+ })(MessageRole || {});
807
+
808
+ // ui/src/bichat/context/chatHelpers.ts
814
809
  var ARTIFACT_TOOL_NAMES = /* @__PURE__ */ new Set([
815
810
  "code_interpreter",
816
811
  "draw_chart",
@@ -896,10 +891,18 @@ function readDebugLimitsFromGlobalContext() {
896
891
  completionReserveTokens
897
892
  };
898
893
  }
894
+ var SessionCtx = React.createContext(null);
895
+ var MessagingCtx = React.createContext(null);
896
+ var InputCtx = React.createContext(null);
897
+ var DEFAULT_RATE_LIMIT_CONFIG = {
898
+ maxRequests: 20,
899
+ windowMs: 6e4
900
+ };
899
901
  function ChatSessionProvider({
900
902
  dataSource,
901
903
  sessionId,
902
904
  rateLimiter: externalRateLimiter,
905
+ rateLimitConfig,
903
906
  children
904
907
  }) {
905
908
  const [currentSessionId, setCurrentSessionId] = React.useState(sessionId);
@@ -924,7 +927,7 @@ function ChatSessionProvider({
924
927
  const [inputError, setInputError] = React.useState(null);
925
928
  const [messageQueue, setMessageQueue] = React.useState([]);
926
929
  const rateLimiterRef = React.useRef(
927
- externalRateLimiter || new RateLimiter(DEFAULT_RATE_LIMIT_CONFIG)
930
+ externalRateLimiter || new RateLimiter(rateLimitConfig || DEFAULT_RATE_LIMIT_CONFIG)
928
931
  );
929
932
  const sessionRef = React.useRef({ currentSessionId, debugMode, debugSessionKey });
930
933
  sessionRef.current = { currentSessionId, debugMode, debugSessionKey };
@@ -1108,7 +1111,6 @@ function ChatSessionProvider({
1108
1111
  const timeUntilNext = rateLimiterRef.current.getTimeUntilNextRequest();
1109
1112
  const seconds = Math.ceil(timeUntilNext / 1e3);
1110
1113
  setError(`Rate limit exceeded. Please wait ${seconds} seconds before sending another message.`);
1111
- setTimeout(() => setError(null), 5e3);
1112
1114
  return;
1113
1115
  }
1114
1116
  setMessage("");
@@ -1128,6 +1130,9 @@ function ChatSessionProvider({
1128
1130
  }
1129
1131
  const replaceIndex = prev.findIndex((turn) => turn.userTurn.id === replaceFromMessageID);
1130
1132
  if (replaceIndex === -1) {
1133
+ console.warn(
1134
+ `[ChatContext] replaceFromMessageID "${replaceFromMessageID}" not found in turns; appending as new turn`
1135
+ );
1131
1136
  return [...prev, tempTurn];
1132
1137
  }
1133
1138
  return [...prev.slice(0, replaceIndex), tempTurn];
@@ -1208,7 +1213,7 @@ function ChatSessionProvider({
1208
1213
  return;
1209
1214
  }
1210
1215
  setTurns((prev) => prev.filter((t) => t.id !== tempTurn.id));
1211
- const errorMessage = err instanceof Error ? err.message : "error.networkError";
1216
+ const errorMessage = err instanceof Error ? err.message : "Error.NetworkError";
1212
1217
  setInputError(errorMessage);
1213
1218
  console.error("Send message error:", err);
1214
1219
  } finally {
@@ -1234,7 +1239,7 @@ function ChatSessionProvider({
1234
1239
  if (!message.trim() && attachments.length === 0) return;
1235
1240
  setInputError(null);
1236
1241
  const convertedAttachments = attachments.map((att) => ({
1237
- id: "",
1242
+ clientKey: att.clientKey || crypto.randomUUID(),
1238
1243
  filename: att.filename,
1239
1244
  mimeType: att.mimeType,
1240
1245
  sizeBytes: att.sizeBytes,
@@ -1461,16 +1466,6 @@ function useChatInput() {
1461
1466
  }
1462
1467
  return context;
1463
1468
  }
1464
- function useChat() {
1465
- const s = useChatSession();
1466
- const m = useChatMessaging();
1467
- const i = useChatInput();
1468
- return React.useMemo(() => ({
1469
- ...s,
1470
- ...m,
1471
- ...i
1472
- }), [s, m, i]);
1473
- }
1474
1469
 
1475
1470
  // ui/src/bichat/components/ChatHeader.tsx
1476
1471
  init_useTranslation();
@@ -1511,8 +1506,8 @@ function useBranding() {
1511
1506
  appName: customBranding.appName || "BiChat",
1512
1507
  logoUrl: customBranding.logoUrl,
1513
1508
  welcome: {
1514
- title: customBranding.welcome?.title || t("welcome.title"),
1515
- description: customBranding.welcome?.description || t("welcome.description"),
1509
+ title: customBranding.welcome?.title || t("Welcome.Title"),
1510
+ description: customBranding.welcome?.description || t("Welcome.Description"),
1516
1511
  examplePrompts
1517
1512
  },
1518
1513
  theme: customBranding.theme
@@ -1528,7 +1523,7 @@ function ChatHeader({ session, onBack, readOnly, logoSlot, actionsSlot }) {
1528
1523
  {
1529
1524
  onClick: onBack,
1530
1525
  className: "cursor-pointer p-2 hover:bg-gray-100 dark:hover:bg-gray-700 active:bg-gray-200 dark:active:bg-gray-600 rounded-lg transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50",
1531
- "aria-label": t("chat.goBack"),
1526
+ "aria-label": t("Chat.GoBack"),
1532
1527
  children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
1533
1528
  }
1534
1529
  ) : null;
@@ -1538,7 +1533,7 @@ function ChatHeader({ session, onBack, readOnly, logoSlot, actionsSlot }) {
1538
1533
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
1539
1534
  BackButton,
1540
1535
  Logo,
1541
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold text-[var(--bichat-text)]", children: t("chat.newChat") })
1536
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-lg font-semibold text-[var(--bichat-text)]", children: t("Chat.NewChat") })
1542
1537
  ] }),
1543
1538
  actionsSlot && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: actionsSlot })
1544
1539
  ] }) });
@@ -1554,14 +1549,14 @@ function ChatHeader({ session, onBack, readOnly, logoSlot, actionsSlot }) {
1554
1549
  className: "w-4 h-4 text-[var(--bichat-primary)]",
1555
1550
  fill: "currentColor",
1556
1551
  viewBox: "0 0 20 20",
1557
- "aria-label": t("chat.pinned"),
1552
+ "aria-label": t("Chat.Pinned"),
1558
1553
  children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 2a1 1 0 011 1v1.323l3.954 1.582 1.599-.8a1 1 0 01.894 1.79l-1.233.616 1.738 5.42a1 1 0 01-.285 1.05A3.989 3.989 0 0115 15a3.989 3.989 0 01-2.667-1.019 1 1 0 01-.285-1.05l1.715-5.349L11 6.477V16h2a1 1 0 110 2H7a1 1 0 110-2h2V6.477L6.237 7.582l1.715 5.349a1 1 0 01-.285 1.05A3.989 3.989 0 015 15a3.989 3.989 0 01-2.667-1.019 1 1 0 01-.285-1.05l1.738-5.42-1.233-.617a1 1 0 01.894-1.788l1.599.799L9 4.323V3a1 1 0 011-1z" })
1559
1554
  }
1560
1555
  )
1561
1556
  ] }),
1562
1557
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
1563
- readOnly && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2 py-1 text-xs bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-200 rounded", children: t("chat.readOnly") }),
1564
- session.status === "archived" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2 py-1 text-xs bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded", children: t("chat.archived") }),
1558
+ readOnly && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2 py-1 text-xs bg-amber-100 dark:bg-amber-900/30 text-amber-800 dark:text-amber-200 rounded", children: t("Chat.ReadOnly") }),
1559
+ session.status === "archived" && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2 py-1 text-xs bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded", children: t("Chat.Archived") }),
1565
1560
  actionsSlot
1566
1561
  ] })
1567
1562
  ] }) });
@@ -1900,7 +1895,7 @@ function FileCard({ attachment, index, onRemove }) {
1900
1895
  onRemove && /* @__PURE__ */ jsxRuntime.jsx(RemoveButton, { index, onRemove, filename: attachment.filename })
1901
1896
  ] });
1902
1897
  }
1903
- var attachmentEq = (a, b) => a.id === b.id && a.filename === b.filename && a.preview === b.preview && a.base64Data === b.base64Data && a.url === b.url;
1898
+ var attachmentEq = (a, b) => a.clientKey === b.clientKey && a.id === b.id && a.filename === b.filename && a.preview === b.preview && a.base64Data === b.base64Data && a.url === b.url;
1904
1899
  var MemoizedImageItem = React__default.default.memo(
1905
1900
  ImageItem,
1906
1901
  (prev, next) => attachmentEq(prev.attachment, next.attachment) && prev.index === next.index && prev.onRemove === next.onRemove && prev.onView === next.onView
@@ -1950,7 +1945,7 @@ function AttachmentGrid({
1950
1945
  onRemove: isEditable ? onRemove : void 0,
1951
1946
  onView
1952
1947
  },
1953
- `${attachment.id || attachment.filename}-${index}`
1948
+ attachment.clientKey
1954
1949
  ) : /* @__PURE__ */ jsxRuntime.jsx(
1955
1950
  MemoizedFileCard,
1956
1951
  {
@@ -1958,7 +1953,7 @@ function AttachmentGrid({
1958
1953
  index,
1959
1954
  onRemove: isEditable ? onRemove : void 0
1960
1955
  },
1961
- `${attachment.id || attachment.filename}-${index}`
1956
+ attachment.clientKey
1962
1957
  );
1963
1958
  }),
1964
1959
  Array.from({ length: pendingCount }).map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(ShimmerCard, {}, `pending-${i}`))
@@ -2366,7 +2361,7 @@ function UserMessage({
2366
2361
  onClick: handleCopyClick,
2367
2362
  className: `cursor-pointer ${classes.actionButton} ${isCopied ? "text-green-600 dark:text-green-400" : ""}`,
2368
2363
  "aria-label": "Copy message",
2369
- title: isCopied ? t("message.copied") : t("message.copy"),
2364
+ title: isCopied ? t("Message.Copied") : t("Message.Copy"),
2370
2365
  children: isCopied ? /* @__PURE__ */ jsxRuntime.jsx(react.Check, { size: 14, weight: "bold" }) : /* @__PURE__ */ jsxRuntime.jsx(react.Copy, { size: 14, weight: "regular" })
2371
2366
  }
2372
2367
  ),
@@ -2408,7 +2403,7 @@ function UserTurnView({
2408
2403
  hideTimestamp,
2409
2404
  allowEdit
2410
2405
  }) {
2411
- const { handleEdit, handleCopy } = useChat();
2406
+ const { handleEdit, handleCopy } = useChatMessaging();
2412
2407
  return /* @__PURE__ */ jsxRuntime.jsx(
2413
2408
  UserMessage,
2414
2409
  {
@@ -2533,7 +2528,7 @@ function SourcesPanel({ citations }) {
2533
2528
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
2534
2529
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 w-5 h-5 bg-[var(--bichat-primary)] text-white rounded-full flex items-center justify-center text-xs", children: index + 1 }),
2535
2530
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1", children: [
2536
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-gray-900 dark:text-gray-100", children: citation.title || citation.source }),
2531
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "font-medium text-gray-900 dark:text-gray-100", children: citation.title }),
2537
2532
  citation.url && /* @__PURE__ */ jsxRuntime.jsx(
2538
2533
  "a",
2539
2534
  {
@@ -2609,7 +2604,7 @@ function DownloadCard({ artifact }) {
2609
2604
  );
2610
2605
  }
2611
2606
  function InlineQuestionForm({ pendingQuestion }) {
2612
- const { handleSubmitQuestionAnswers, handleRejectPendingQuestion, loading } = useChat();
2607
+ const { handleSubmitQuestionAnswers, handleRejectPendingQuestion, loading } = useChatMessaging();
2613
2608
  const [currentStep, setCurrentStep] = React.useState(0);
2614
2609
  const [answers, setAnswers] = React.useState({});
2615
2610
  const [otherTexts, setOtherTexts] = React.useState({});
@@ -3043,13 +3038,13 @@ function ToolCard({ tool }) {
3043
3038
  children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden min-h-0", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 pb-3 pt-1 space-y-2", children: [
3044
3039
  tool.arguments && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg bg-[#1a1b26] dark:bg-gray-950 overflow-hidden ring-1 ring-gray-800/10 dark:ring-white/5", children: [
3045
3040
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-3 py-1.5 bg-[#1e1f2e] dark:bg-gray-900/80 border-b border-white/5", children: [
3046
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] uppercase tracking-wider font-medium text-gray-500", children: t("slash.debugArguments") }),
3041
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] uppercase tracking-wider font-medium text-gray-500", children: t("Slash.DebugArguments") }),
3047
3042
  /* @__PURE__ */ jsxRuntime.jsx(
3048
3043
  CopyPill,
3049
3044
  {
3050
3045
  text: tool.arguments,
3051
- label: t("slash.debugCopyTrace"),
3052
- copiedLabel: t("slash.debugCopied")
3046
+ label: t("Slash.DebugCopyTrace"),
3047
+ copiedLabel: t("Slash.DebugCopied")
3053
3048
  }
3054
3049
  )
3055
3050
  ] }),
@@ -3057,20 +3052,20 @@ function ToolCard({ tool }) {
3057
3052
  ] }),
3058
3053
  tool.result && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg bg-[#1a1b26] dark:bg-gray-950 overflow-hidden ring-1 ring-gray-800/10 dark:ring-white/5", children: [
3059
3054
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-3 py-1.5 bg-[#1e1f2e] dark:bg-gray-900/80 border-b border-white/5", children: [
3060
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] uppercase tracking-wider font-medium text-gray-500", children: t("slash.debugResult") }),
3055
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] uppercase tracking-wider font-medium text-gray-500", children: t("Slash.DebugResult") }),
3061
3056
  /* @__PURE__ */ jsxRuntime.jsx(
3062
3057
  CopyPill,
3063
3058
  {
3064
3059
  text: tool.result,
3065
- label: t("slash.debugCopyTrace"),
3066
- copiedLabel: t("slash.debugCopied")
3060
+ label: t("Slash.DebugCopyTrace"),
3061
+ copiedLabel: t("Slash.DebugCopied")
3067
3062
  }
3068
3063
  )
3069
3064
  ] }),
3070
3065
  /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "p-3 text-[11px] font-mono text-gray-300 overflow-x-auto max-h-60 overflow-y-auto whitespace-pre-wrap break-all leading-relaxed", children: tool.result })
3071
3066
  ] }),
3072
3067
  tool.error && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg bg-red-950/80 dark:bg-red-950/40 overflow-hidden ring-1 ring-red-800/20", children: [
3073
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-1.5 border-b border-red-800/20", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] uppercase tracking-wider font-medium text-red-400", children: t("slash.debugError") }) }),
3068
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-1.5 border-b border-red-800/20", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] uppercase tracking-wider font-medium text-red-400", children: t("Slash.DebugError") }) }),
3074
3069
  /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "p-3 text-[11px] font-mono text-red-300 overflow-x-auto whitespace-pre-wrap break-all leading-relaxed", children: tool.error })
3075
3070
  ] })
3076
3071
  ] }) })
@@ -3090,7 +3085,7 @@ function DebugPanel({ trace }) {
3090
3085
  metrics.push({
3091
3086
  icon: /* @__PURE__ */ jsxRuntime.jsx(react.Timer, { size: 14, weight: "duotone", className: "text-amber-600 dark:text-amber-400" }),
3092
3087
  value: formatGenerationDuration(trace.generationMs),
3093
- label: t("slash.debugGeneration"),
3088
+ label: t("Slash.DebugGeneration"),
3094
3089
  accentBorder: "border-l-amber-400 dark:border-l-amber-500",
3095
3090
  accentBg: "bg-amber-50 dark:bg-amber-950/30"
3096
3091
  });
@@ -3099,7 +3094,7 @@ function DebugPanel({ trace }) {
3099
3094
  metrics.push({
3100
3095
  icon: /* @__PURE__ */ jsxRuntime.jsx(react.Lightning, { size: 14, weight: "fill", className: "text-orange-500 dark:text-orange-400" }),
3101
3096
  value: `${tokensPerSecond.toFixed(1)}/s`,
3102
- label: t("slash.debugTokensPerSecond"),
3097
+ label: t("Slash.DebugTokensPerSecond"),
3103
3098
  accentBorder: "border-l-orange-400 dark:border-l-orange-500",
3104
3099
  accentBg: "bg-orange-50 dark:bg-orange-950/30"
3105
3100
  });
@@ -3109,21 +3104,21 @@ function DebugPanel({ trace }) {
3109
3104
  {
3110
3105
  icon: /* @__PURE__ */ jsxRuntime.jsx(react.Stack, { size: 14, weight: "duotone", className: "text-violet-600 dark:text-violet-400" }),
3111
3106
  value: trace.usage.totalTokens.toLocaleString(),
3112
- label: t("slash.debugTotalTokens"),
3107
+ label: t("Slash.DebugTotalTokens"),
3113
3108
  accentBorder: "border-l-violet-400 dark:border-l-violet-500",
3114
3109
  accentBg: "bg-violet-50 dark:bg-violet-950/30"
3115
3110
  },
3116
3111
  {
3117
3112
  icon: /* @__PURE__ */ jsxRuntime.jsx(react.ArrowUp, { size: 14, weight: "bold", className: "text-blue-600 dark:text-blue-400" }),
3118
3113
  value: trace.usage.promptTokens.toLocaleString(),
3119
- label: t("slash.debugPromptTokens"),
3114
+ label: t("Slash.DebugPromptTokens"),
3120
3115
  accentBorder: "border-l-blue-400 dark:border-l-blue-500",
3121
3116
  accentBg: "bg-blue-50 dark:bg-blue-950/30"
3122
3117
  },
3123
3118
  {
3124
3119
  icon: /* @__PURE__ */ jsxRuntime.jsx(react.ArrowDown, { size: 14, weight: "bold", className: "text-indigo-600 dark:text-indigo-400" }),
3125
3120
  value: trace.usage.completionTokens.toLocaleString(),
3126
- label: t("slash.debugCompletionTokens"),
3121
+ label: t("Slash.DebugCompletionTokens"),
3127
3122
  accentBorder: "border-l-indigo-400 dark:border-l-indigo-500",
3128
3123
  accentBg: "bg-indigo-50 dark:bg-indigo-950/30"
3129
3124
  }
@@ -3132,7 +3127,7 @@ function DebugPanel({ trace }) {
3132
3127
  metrics.push({
3133
3128
  icon: /* @__PURE__ */ jsxRuntime.jsx(react.Database, { size: 14, weight: "duotone", className: "text-pink-600 dark:text-pink-400" }),
3134
3129
  value: trace.usage.cachedTokens.toLocaleString(),
3135
- label: t("slash.debugCachedTokens"),
3130
+ label: t("Slash.DebugCachedTokens"),
3136
3131
  accentBorder: "border-l-pink-400 dark:border-l-pink-500",
3137
3132
  accentBg: "bg-pink-50 dark:bg-pink-950/30"
3138
3133
  });
@@ -3143,14 +3138,14 @@ function DebugPanel({ trace }) {
3143
3138
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-4", children: [
3144
3139
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
3145
3140
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center w-6 h-6 rounded-lg bg-gray-100 dark:bg-gray-800", children: /* @__PURE__ */ jsxRuntime.jsx(react.Bug, { size: 14, weight: "duotone", className: "text-gray-500 dark:text-gray-400" }) }),
3146
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-[11px] uppercase tracking-widest font-semibold text-gray-400 dark:text-gray-500", children: t("slash.debugPanelTitle") })
3141
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-[11px] uppercase tracking-widest font-semibold text-gray-400 dark:text-gray-500", children: t("Slash.DebugPanelTitle") })
3147
3142
  ] }),
3148
3143
  hasData && trace && /* @__PURE__ */ jsxRuntime.jsx(
3149
3144
  CopyPill,
3150
3145
  {
3151
3146
  text: JSON.stringify(trace, null, 2),
3152
- label: t("slash.debugCopyTrace"),
3153
- copiedLabel: t("slash.debugCopied")
3147
+ label: t("Slash.DebugCopyTrace"),
3148
+ copiedLabel: t("Slash.DebugCopied")
3154
3149
  }
3155
3150
  )
3156
3151
  ] }),
@@ -3159,12 +3154,12 @@ function DebugPanel({ trace }) {
3159
3154
  trace.tools.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3160
3155
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 mb-2.5", children: [
3161
3156
  /* @__PURE__ */ jsxRuntime.jsx(react.Wrench, { size: 13, weight: "duotone", className: "text-gray-400 dark:text-gray-500" }),
3162
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-medium text-gray-500 dark:text-gray-400", children: t("slash.debugToolCalls") }),
3157
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-medium text-gray-500 dark:text-gray-400", children: t("Slash.DebugToolCalls") }),
3163
3158
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-1.5 py-0.5 rounded-full bg-gray-100 dark:bg-gray-800 text-[10px] font-mono font-medium text-gray-500 dark:text-gray-400 tabular-nums", children: trace.tools.length })
3164
3159
  ] }),
3165
3160
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: trace.tools.map((tool, idx) => /* @__PURE__ */ jsxRuntime.jsx(ToolCard, { tool }, `${tool.callId || tool.name}-${idx}`)) })
3166
3161
  ] })
3167
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-400 dark:text-gray-500 italic", children: t("slash.debugUnavailable") })
3162
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-400 dark:text-gray-500 italic", children: t("Slash.DebugUnavailable") })
3168
3163
  ] });
3169
3164
  }
3170
3165
 
@@ -3370,7 +3365,7 @@ function AssistantMessage({
3370
3365
  )
3371
3366
  }
3372
3367
  ),
3373
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: t("assistant.explanation") })
3368
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: t("Assistant.Explanation") })
3374
3369
  ]
3375
3370
  }
3376
3371
  ),
@@ -3396,7 +3391,7 @@ function AssistantMessage({
3396
3391
  onClick: handleCopyClick,
3397
3392
  className: `cursor-pointer ${classes.actionButton} ${isCopied ? "text-green-600 dark:text-green-400" : ""}`,
3398
3393
  "aria-label": "Copy message",
3399
- title: isCopied ? t("message.copied") : t("message.copy"),
3394
+ title: isCopied ? t("Message.Copied") : t("Message.Copy"),
3400
3395
  children: isCopied ? /* @__PURE__ */ jsxRuntime.jsx(react.Check, { size: 14, weight: "bold" }) : /* @__PURE__ */ jsxRuntime.jsx(react.Copy, { size: 14, weight: "regular" })
3401
3396
  }
3402
3397
  ),
@@ -3490,7 +3485,7 @@ function SystemMessage({
3490
3485
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-4 pt-3 pb-2", children: [
3491
3486
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-gray-400 dark:text-gray-500", children: [
3492
3487
  /* @__PURE__ */ jsxRuntime.jsx(react.ClockCounterClockwise, { size: 13, weight: "bold" }),
3493
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-semibold uppercase tracking-wider", children: t("system.conversationSummary") })
3488
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-semibold uppercase tracking-wider", children: t("System.ConversationSummary") })
3494
3489
  ] }),
3495
3490
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1" }),
3496
3491
  !hideActions && !hideTimestamp && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] text-gray-400 dark:text-gray-500 tabular-nums", children: timestamp }),
@@ -3504,7 +3499,7 @@ function SystemMessage({
3504
3499
  ${isCopied ? "text-green-600 dark:text-green-400" : "text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-200/50 dark:hover:bg-gray-700/40"}
3505
3500
  `,
3506
3501
  "aria-label": "Copy message",
3507
- title: isCopied ? t("message.copied") : t("message.copy"),
3502
+ title: isCopied ? t("Message.Copied") : t("Message.Copy"),
3508
3503
  children: isCopied ? /* @__PURE__ */ jsxRuntime.jsx(react.Check, { size: 13, weight: "bold" }) : /* @__PURE__ */ jsxRuntime.jsx(react.Copy, { size: 13, weight: "regular" })
3509
3504
  }
3510
3505
  )
@@ -3522,7 +3517,7 @@ function SystemMessage({
3522
3517
  {
3523
3518
  fallback: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-sm text-gray-400 dark:text-gray-500 py-2", children: [
3524
3519
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-3.5 h-3.5 border-[1.5px] border-gray-300 dark:border-gray-600 border-t-transparent rounded-full animate-spin" }),
3525
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", children: t("system.loadingSummary") })
3520
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", children: t("System.LoadingSummary") })
3526
3521
  ] }),
3527
3522
  children: /* @__PURE__ */ jsxRuntime.jsx(MarkdownRenderer3, { content, sendDisabled: true })
3528
3523
  }
@@ -3539,7 +3534,7 @@ function SystemMessage({
3539
3534
  "aria-expanded": isExpanded,
3540
3535
  className: "cursor-pointer group/toggle inline-flex items-center gap-1 px-3 py-1 rounded-full text-[11px] font-medium text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 hover:bg-gray-200/60 dark:hover:bg-gray-700/50 transition-colors duration-150",
3541
3536
  children: [
3542
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: isExpanded ? t("system.showLess") : t("system.showMore") }),
3537
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: isExpanded ? t("System.ShowLess") : t("System.ShowMore") }),
3543
3538
  /* @__PURE__ */ jsxRuntime.jsx(
3544
3539
  react.CaretDown,
3545
3540
  {
@@ -3564,7 +3559,8 @@ function AssistantTurnView({
3564
3559
  hideActions,
3565
3560
  hideTimestamp
3566
3561
  }) {
3567
- const { handleCopy, handleRegenerate, pendingQuestion, sendMessage, loading, debugMode } = useChat();
3562
+ const { debugMode } = useChatSession();
3563
+ const { handleCopy, handleRegenerate, pendingQuestion, sendMessage, loading } = useChatMessaging();
3568
3564
  const assistantTurn = turn.assistantTurn;
3569
3565
  if (!assistantTurn) return null;
3570
3566
  if (assistantTurn.role === "system") {
@@ -4050,15 +4046,8 @@ var MarkdownRenderer4 = React.lazy(
4050
4046
  );
4051
4047
  function MessageList({ renderUserTurn, renderAssistantTurn, thinkingVerbs, readOnly }) {
4052
4048
  const { t } = useTranslation();
4053
- const {
4054
- turns,
4055
- streamingContent,
4056
- isStreaming,
4057
- loading,
4058
- isCompacting,
4059
- currentSessionId,
4060
- fetching
4061
- } = useChat();
4049
+ const { currentSessionId, fetching } = useChatSession();
4050
+ const { turns, streamingContent, isStreaming, loading, isCompacting } = useChatMessaging();
4062
4051
  const messagesEndRef = React.useRef(null);
4063
4052
  const containerRef = React.useRef(null);
4064
4053
  const initialScrollSessionRef = React.useRef(void 0);
@@ -4117,8 +4106,8 @@ function MessageList({ renderUserTurn, renderAssistantTurn, thinkingVerbs, readO
4117
4106
  isCompacting && /* @__PURE__ */ jsxRuntime.jsx(
4118
4107
  CompactionDoodle_default,
4119
4108
  {
4120
- title: t("slash.compactingTitle"),
4121
- subtitle: t("slash.compactingSubtitle")
4109
+ title: t("Slash.CompactingTitle"),
4110
+ subtitle: t("Slash.CompactingSubtitle")
4122
4111
  }
4123
4112
  ),
4124
4113
  fetching && turns.length === 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", "aria-hidden": "true", children: [
@@ -4219,7 +4208,7 @@ var MessageInput = React.forwardRef(
4219
4208
  const [dropSuccess, setDropSuccess] = React.useState(false);
4220
4209
  const [pendingFileCount, setPendingFileCount] = React.useState(0);
4221
4210
  const [viewingImageIndex, setViewingImageIndex] = React.useState(null);
4222
- const placeholder = placeholderOverride || t("input.placeholder");
4211
+ const placeholder = placeholderOverride || t("Input.Placeholder");
4223
4212
  const textareaRef = React.useRef(null);
4224
4213
  const fileInputRef = React.useRef(null);
4225
4214
  const containerRef = React.useRef(null);
@@ -4230,9 +4219,9 @@ var MessageInput = React.forwardRef(
4230
4219
  const commandQuery = message.trimStart().slice(1).split(/\s+/)[0]?.toLowerCase() || "";
4231
4220
  const slashCommands = React.useMemo(
4232
4221
  () => [
4233
- { name: "/clear", description: t("slash.clearDescription") },
4234
- { name: "/debug", description: t("slash.debugDescription") },
4235
- { name: "/compact", description: t("slash.compactDescription") }
4222
+ { name: "/clear", description: t("Slash.ClearDescription") },
4223
+ { name: "/debug", description: t("Slash.DebugDescription") },
4224
+ { name: "/compact", description: t("Slash.CompactDescription") }
4236
4225
  ],
4237
4226
  [t]
4238
4227
  );
@@ -4315,7 +4304,7 @@ var MessageInput = React.forwardRef(
4315
4304
  const base64Results = await Promise.all(fileArray.map(convertToBase64));
4316
4305
  const newAttachments = fileArray.map((file, i) => {
4317
4306
  const attachment = {
4318
- id: "",
4307
+ clientKey: crypto.randomUUID(),
4319
4308
  filename: file.name,
4320
4309
  mimeType: file.type,
4321
4310
  sizeBytes: file.size,
@@ -4522,12 +4511,12 @@ var MessageInput = React.forwardRef(
4522
4511
  onClearCommandError?.();
4523
4512
  },
4524
4513
  className: "cursor-pointer ml-2 p-1 hover:bg-red-100 dark:hover:bg-red-800 rounded transition-colors",
4525
- "aria-label": t("input.dismissError"),
4514
+ "aria-label": t("Input.DismissError"),
4526
4515
  children: /* @__PURE__ */ jsxRuntime.jsx(react.X, { size: 14 })
4527
4516
  }
4528
4517
  )
4529
4518
  ] }),
4530
- messageQueue.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-3 text-xs text-gray-500 dark:text-gray-400", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2.5 py-1 bg-primary-50 dark:bg-primary-900/30 text-primary-600 dark:text-primary-400 rounded font-medium", children: t("input.messagesQueued", { count: messageQueue.length }) }) }),
4519
+ messageQueue.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-3 text-xs text-gray-500 dark:text-gray-400", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-2.5 py-1 bg-primary-50 dark:bg-primary-900/30 text-primary-600 dark:text-primary-400 rounded font-medium", children: t("Input.MessagesQueued", { count: messageQueue.length }) }) }),
4531
4520
  debugMode && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3 space-y-2 text-xs", children: [
4532
4521
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5 px-2.5 py-1 bg-amber-100 dark:bg-amber-900/40 text-amber-700 dark:text-amber-300 rounded-full font-medium text-[11px]", children: [
4533
4522
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-1.5 w-1.5", "aria-hidden": "true", children: [
@@ -4535,49 +4524,49 @@ var MessageInput = React.forwardRef(
4535
4524
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "relative inline-flex rounded-full h-1.5 w-1.5 bg-amber-500" })
4536
4525
  ] }),
4537
4526
  /* @__PURE__ */ jsxRuntime.jsx(react.Bug, { size: 12 }),
4538
- t("slash.debugBadge")
4527
+ t("Slash.DebugBadge")
4539
4528
  ] }),
4540
4529
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-xl border border-gray-200/60 dark:border-gray-700/40 bg-gray-50/50 dark:bg-gray-800/30 p-3 space-y-3", children: [
4541
4530
  hasUsage ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-3 gap-1.5", children: [
4542
4531
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-1 py-2 rounded-lg bg-white dark:bg-gray-800/60 border border-gray-100 dark:border-gray-700/30", children: [
4543
4532
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 text-[10px] text-gray-400 dark:text-gray-500", children: [
4544
4533
  /* @__PURE__ */ jsxRuntime.jsx(react.ArrowUp, { size: 10, weight: "bold", className: "text-blue-500 dark:text-blue-400" }),
4545
- t("slash.debugPromptTokens")
4534
+ t("Slash.DebugPromptTokens")
4546
4535
  ] }),
4547
4536
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono font-semibold text-xs text-gray-900 dark:text-gray-100 tabular-nums", children: formatTokens(sessionPromptTokens) })
4548
4537
  ] }),
4549
4538
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-1 py-2 rounded-lg bg-white dark:bg-gray-800/60 border border-gray-100 dark:border-gray-700/30", children: [
4550
4539
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 text-[10px] text-gray-400 dark:text-gray-500", children: [
4551
4540
  /* @__PURE__ */ jsxRuntime.jsx(react.ArrowDown, { size: 10, weight: "bold", className: "text-indigo-500 dark:text-indigo-400" }),
4552
- t("slash.debugCompletionTokens")
4541
+ t("Slash.DebugCompletionTokens")
4553
4542
  ] }),
4554
4543
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono font-semibold text-xs text-gray-900 dark:text-gray-100 tabular-nums", children: formatTokens(sessionCompletionTokens) })
4555
4544
  ] }),
4556
4545
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-1 py-2 rounded-lg bg-white dark:bg-gray-800/60 border border-gray-100 dark:border-gray-700/30", children: [
4557
4546
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 text-[10px] text-gray-400 dark:text-gray-500", children: [
4558
4547
  /* @__PURE__ */ jsxRuntime.jsx(react.Stack, { size: 10, weight: "bold", className: "text-violet-500 dark:text-violet-400" }),
4559
- t("slash.debugTotalTokens")
4548
+ t("Slash.DebugTotalTokens")
4560
4549
  ] }),
4561
4550
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono font-semibold text-xs text-gray-900 dark:text-gray-100 tabular-nums", children: formatTokens(sessionTotalTokens) })
4562
4551
  ] })
4563
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-gray-400 dark:text-gray-500 text-center py-1", children: t("slash.debugSessionUsageUnavailable") }),
4552
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-gray-400 dark:text-gray-500 text-center py-1", children: t("Slash.DebugSessionUsageUnavailable") }),
4564
4553
  debugLimits && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-3 gap-1.5", children: [
4565
4554
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 py-2 px-2 rounded-lg bg-white dark:bg-gray-800/60 border border-gray-100 dark:border-gray-700/30", children: [
4566
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: t("slash.debugPolicyMaxContextWindow") }),
4555
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: t("Slash.DebugPolicyMaxContextWindow") }),
4567
4556
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono font-semibold text-xs text-gray-900 dark:text-gray-100 tabular-nums", children: formatTokens(policyMaxTokens) })
4568
4557
  ] }),
4569
4558
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 py-2 px-2 rounded-lg bg-white dark:bg-gray-800/60 border border-gray-100 dark:border-gray-700/30", children: [
4570
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: t("slash.debugModelMaxContextWindow") }),
4559
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: t("Slash.DebugModelMaxContextWindow") }),
4571
4560
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono font-semibold text-xs text-gray-900 dark:text-gray-100 tabular-nums", children: formatTokens(modelMaxTokens) })
4572
4561
  ] }),
4573
4562
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1 py-2 px-2 rounded-lg bg-white dark:bg-gray-800/60 border border-gray-100 dark:border-gray-700/30", children: [
4574
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: t("slash.debugEffectiveContextWindow") }),
4563
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: t("Slash.DebugEffectiveContextWindow") }),
4575
4564
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono font-semibold text-xs text-gray-900 dark:text-gray-100 tabular-nums", children: formatTokens(effectiveMaxTokens) })
4576
4565
  ] })
4577
4566
  ] }),
4578
4567
  effectiveMaxTokens > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1.5", children: [
4579
4568
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
4580
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: t("slash.debugContextUsage") }),
4569
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-gray-400 dark:text-gray-500", children: t("Slash.DebugContextUsage") }),
4581
4570
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
4582
4571
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono text-[10px] text-gray-400 dark:text-gray-500 tabular-nums", children: [
4583
4572
  formatTokens(latestPromptTokens),
@@ -4627,9 +4616,9 @@ var MessageInput = React.forwardRef(
4627
4616
  children: [
4628
4617
  isDragging && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-10 bg-primary-50/95 dark:bg-primary-900/90 border-2 border-dashed border-primary-400 rounded-2xl flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-2", children: [
4629
4618
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-10 h-10 rounded-full bg-primary-100 dark:bg-primary-800 flex items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(react.Paperclip, { size: 20, className: "text-primary-600 dark:text-primary-400" }) }),
4630
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-primary-700 dark:text-primary-300 font-medium", children: t("input.dropFiles") })
4619
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-primary-700 dark:text-primary-300 font-medium", children: t("Input.DropFiles") })
4631
4620
  ] }) }),
4632
- dropSuccess && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-10 bg-green-50/95 dark:bg-green-900/90 border-2 border-green-400 rounded-2xl flex items-center justify-center animate-pulse pointer-events-none", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-green-700 dark:text-green-300 font-medium", children: t("input.filesAdded") }) }),
4621
+ dropSuccess && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-10 bg-green-50/95 dark:bg-green-900/90 border-2 border-green-400 rounded-2xl flex items-center justify-center animate-pulse pointer-events-none", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-green-700 dark:text-green-300 font-medium", children: t("Input.FilesAdded") }) }),
4633
4622
  /* @__PURE__ */ jsxRuntime.jsxs(
4634
4623
  "div",
4635
4624
  {
@@ -4642,8 +4631,8 @@ var MessageInput = React.forwardRef(
4642
4631
  onClick: () => fileInputRef.current?.click(),
4643
4632
  disabled: loading || disabled || attachments.length >= maxFiles,
4644
4633
  className: "cursor-pointer flex-shrink-0 self-center p-2 text-gray-500 dark:text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors disabled:opacity-40 disabled:cursor-not-allowed",
4645
- "aria-label": t("input.attachFiles"),
4646
- title: t("input.attachFiles"),
4634
+ "aria-label": t("Input.AttachFiles"),
4635
+ title: t("Input.AttachFiles"),
4647
4636
  children: /* @__PURE__ */ jsxRuntime.jsx(react.Paperclip, { size: 20 })
4648
4637
  }
4649
4638
  ),
@@ -4656,7 +4645,7 @@ var MessageInput = React.forwardRef(
4656
4645
  multiple: true,
4657
4646
  onChange: handleFileInputChange,
4658
4647
  className: "hidden",
4659
- "aria-label": t("input.fileInput")
4648
+ "aria-label": t("Input.FileInput")
4660
4649
  }
4661
4650
  ),
4662
4651
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 self-stretch flex items-center", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -4686,7 +4675,7 @@ var MessageInput = React.forwardRef(
4686
4675
  rows: 1,
4687
4676
  disabled: loading || disabled,
4688
4677
  "aria-busy": loading,
4689
- "aria-label": t("input.messageInput")
4678
+ "aria-label": t("Input.MessageInput")
4690
4679
  }
4691
4680
  ) }),
4692
4681
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -4695,15 +4684,15 @@ var MessageInput = React.forwardRef(
4695
4684
  type: "submit",
4696
4685
  disabled: !canSubmit,
4697
4686
  className: "cursor-pointer flex-shrink-0 self-center p-2 rounded-lg bg-primary-600 hover:bg-primary-700 active:bg-primary-800 active:scale-95 text-white shadow-sm transition-all disabled:opacity-40 disabled:cursor-not-allowed disabled:hover:bg-primary-600",
4698
- "aria-label": loading ? t("input.processing") : t("input.sendMessage"),
4687
+ "aria-label": loading ? t("Input.Processing") : t("Input.SendMessage"),
4699
4688
  children: loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-[18px] h-[18px] border-2 border-white/60 border-t-transparent rounded-full animate-spin" }) : /* @__PURE__ */ jsxRuntime.jsx(react.PaperPlaneRight, { size: 18, weight: "fill" })
4700
4689
  }
4701
4690
  )
4702
4691
  ]
4703
4692
  }
4704
4693
  ),
4705
- isFocused && !message && !loading && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:block absolute -bottom-5 left-14 text-[10px] text-gray-400 dark:text-gray-500 select-none animate-fade-in", children: t("input.shiftEnterHint") }),
4706
- isCommandListVisible && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0 right-0 bottom-full mb-1.5 z-20 overflow-hidden rounded-lg border border-gray-200/70 bg-white/98 shadow-md backdrop-blur-xl dark:border-gray-700/70 dark:bg-gray-900/98 dark:shadow-black/20", children: filteredCommands.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("ul", { role: "listbox", "aria-label": t("slash.commandsList"), className: "py-1 px-1", children: filteredCommands.map((command, index) => {
4694
+ isFocused && !message && !loading && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:block absolute -bottom-5 left-14 text-[10px] text-gray-400 dark:text-gray-500 select-none animate-fade-in", children: t("Input.ShiftEnterHint") }),
4695
+ isCommandListVisible && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute left-0 right-0 bottom-full mb-1.5 z-20 overflow-hidden rounded-lg border border-gray-200/70 bg-white/98 shadow-md backdrop-blur-xl dark:border-gray-700/70 dark:bg-gray-900/98 dark:shadow-black/20", children: filteredCommands.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("ul", { role: "listbox", "aria-label": t("Slash.CommandsList"), className: "py-1 px-1", children: filteredCommands.map((command, index) => {
4707
4696
  const isActive = index === activeCommandIndex;
4708
4697
  return /* @__PURE__ */ jsxRuntime.jsxs(
4709
4698
  "li",
@@ -4729,7 +4718,7 @@ var MessageInput = React.forwardRef(
4729
4718
  },
4730
4719
  command.name
4731
4720
  );
4732
- }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2.5 text-center", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-gray-400 dark:text-gray-500", children: t("slash.noMatches") }) }) })
4721
+ }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-2.5 text-center", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-gray-400 dark:text-gray-500", children: t("Slash.NoMatches") }) }) })
4733
4722
  ]
4734
4723
  }
4735
4724
  ),
@@ -4833,8 +4822,8 @@ function WelcomeContent({
4833
4822
  }) {
4834
4823
  const { t } = useTranslation();
4835
4824
  const shouldReduceMotion = framerMotion.useReducedMotion();
4836
- const resolvedTitle = title || t("welcome.title");
4837
- const resolvedDescription = description || t("welcome.description");
4825
+ const resolvedTitle = title || t("Welcome.Title");
4826
+ const resolvedDescription = description || t("Welcome.Description");
4838
4827
  const handlePromptClick = (prompt) => {
4839
4828
  if (onPromptSelect && !disabled) {
4840
4829
  onPromptSelect(prompt);
@@ -4877,7 +4866,7 @@ function WelcomeContent({
4877
4866
  /* @__PURE__ */ jsxRuntime.jsxs(framerMotion.motion.div, { variants: activeItemVariants, children: [
4878
4867
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-4 mb-5", children: [
4879
4868
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px flex-1 bg-gradient-to-r from-transparent to-gray-200 dark:to-gray-700/70" }),
4880
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-semibold uppercase tracking-[0.12em] text-gray-400 dark:text-gray-500 select-none", children: t("welcome.quickStart") }),
4869
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-semibold uppercase tracking-[0.12em] text-gray-400 dark:text-gray-500 select-none", children: t("Welcome.QuickStart") }),
4881
4870
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-px flex-1 bg-gradient-to-l from-transparent to-gray-200 dark:to-gray-700/70" })
4882
4871
  ] }),
4883
4872
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid gap-3 sm:grid-cols-2 lg:grid-cols-3", children: EXAMPLE_PROMPTS.map((prompt, index) => {
@@ -4932,11 +4921,11 @@ init_useTranslation();
4932
4921
  // ui/src/bichat/components/SessionArtifactList.tsx
4933
4922
  init_useTranslation();
4934
4923
  var TYPE_LABEL_KEYS = {
4935
- chart: "artifacts.groupCharts",
4936
- code_output: "artifacts.groupCodeOutputs",
4937
- export: "artifacts.groupExports",
4938
- attachment: "artifacts.groupAttachments",
4939
- other: "artifacts.groupOther"
4924
+ chart: "Artifacts.GroupCharts",
4925
+ code_output: "Artifacts.GroupCodeOutputs",
4926
+ export: "Artifacts.GroupExports",
4927
+ attachment: "Artifacts.GroupAttachments",
4928
+ other: "Artifacts.GroupOther"
4940
4929
  };
4941
4930
  function getGroupIcon(type) {
4942
4931
  const cls = "h-3.5 w-3.5";
@@ -5011,8 +5000,8 @@ function SessionArtifactList({
5011
5000
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-3 px-4 py-12 text-center", children: [
5012
5001
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-12 w-12 items-center justify-center rounded-xl bg-gray-100 dark:bg-gray-800", children: /* @__PURE__ */ jsxRuntime.jsx(react.Package, { className: "h-6 w-6 text-gray-400 dark:text-gray-500", weight: "duotone" }) }),
5013
5002
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
5014
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-500 dark:text-gray-400", children: t("artifacts.empty") }),
5015
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-xs text-gray-400 dark:text-gray-500", children: t("artifacts.emptySubtitle") })
5003
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-gray-500 dark:text-gray-400", children: t("Artifacts.Empty") }),
5004
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-xs text-gray-400 dark:text-gray-500", children: t("Artifacts.EmptySubtitle") })
5016
5005
  ] })
5017
5006
  ] });
5018
5007
  }
@@ -5124,7 +5113,7 @@ function ArtifactActions({ url }) {
5124
5113
  className: "inline-flex items-center gap-2 rounded-lg border border-gray-200 px-3 py-1.5 text-xs font-medium text-gray-700 transition-colors hover:bg-gray-50 dark:border-gray-700 dark:text-gray-200 dark:hover:bg-gray-800",
5125
5114
  children: [
5126
5115
  /* @__PURE__ */ jsxRuntime.jsx(react.ArrowSquareOut, { className: "h-3.5 w-3.5", weight: "bold" }),
5127
- t("artifacts.openInNewTab")
5116
+ t("Artifacts.OpenInNewTab")
5128
5117
  ]
5129
5118
  }
5130
5119
  ),
@@ -5138,7 +5127,7 @@ function ArtifactActions({ url }) {
5138
5127
  className: "inline-flex items-center gap-2 rounded-lg bg-primary-600 px-3 py-1.5 text-xs font-medium text-white shadow-sm transition-colors hover:bg-primary-700",
5139
5128
  children: [
5140
5129
  /* @__PURE__ */ jsxRuntime.jsx(react.DownloadSimple, { className: "h-3.5 w-3.5", weight: "bold" }),
5141
- t("artifacts.download")
5130
+ t("Artifacts.Download")
5142
5131
  ]
5143
5132
  }
5144
5133
  )
@@ -5153,7 +5142,7 @@ function TextArtifactPreview({ artifact }) {
5153
5142
  React.useEffect(() => {
5154
5143
  if (!artifact.url) {
5155
5144
  setLoading(false);
5156
- setError(t("artifacts.textPreviewFailed"));
5145
+ setError(t("Artifacts.TextPreviewFailed"));
5157
5146
  return;
5158
5147
  }
5159
5148
  const controller = new AbortController();
@@ -5176,7 +5165,7 @@ function TextArtifactPreview({ artifact }) {
5176
5165
  if (err instanceof Error && err.name === "AbortError") {
5177
5166
  return;
5178
5167
  }
5179
- setError(t("artifacts.textPreviewFailed"));
5168
+ setError(t("Artifacts.TextPreviewFailed"));
5180
5169
  }).finally(() => {
5181
5170
  setLoading(false);
5182
5171
  });
@@ -5187,15 +5176,15 @@ function TextArtifactPreview({ artifact }) {
5187
5176
  if (loading) {
5188
5177
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-[320px] items-center justify-center rounded-xl border border-gray-200 bg-gray-50 text-sm text-gray-500 dark:border-gray-700/60 dark:bg-gray-800/30 dark:text-gray-400", children: [
5189
5178
  /* @__PURE__ */ jsxRuntime.jsx(react.SpinnerGap, { className: "mr-2 h-4 w-4 animate-spin" }),
5190
- t("artifacts.previewLoading")
5179
+ t("Artifacts.PreviewLoading")
5191
5180
  ] });
5192
5181
  }
5193
5182
  if (error) {
5194
5183
  return /* @__PURE__ */ jsxRuntime.jsx(WarningBox, { message: error });
5195
5184
  }
5196
5185
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
5197
- /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "max-h-[70vh] overflow-auto rounded-xl border border-gray-200 bg-gray-50 p-3 text-xs leading-relaxed text-gray-800 dark:border-gray-700/60 dark:bg-gray-900 dark:text-gray-100", children: content || t("artifacts.previewUnavailable") }),
5198
- truncated && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: t("artifacts.textPreviewTruncated") })
5186
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { className: "max-h-[70vh] overflow-auto rounded-xl border border-gray-200 bg-gray-50 p-3 text-xs leading-relaxed text-gray-800 dark:border-gray-700/60 dark:bg-gray-900 dark:text-gray-100", children: content || t("Artifacts.PreviewUnavailable") }),
5187
+ truncated && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-gray-500 dark:text-gray-400", children: t("Artifacts.TextPreviewTruncated") })
5199
5188
  ] });
5200
5189
  }
5201
5190
  function SessionArtifactPreview({ artifact }) {
@@ -5211,11 +5200,11 @@ function SessionArtifactPreview({ artifact }) {
5211
5200
  if (chartData) {
5212
5201
  return /* @__PURE__ */ jsxRuntime.jsx(ChartCard, { chartData });
5213
5202
  }
5214
- return /* @__PURE__ */ jsxRuntime.jsx(WarningBox, { message: t("artifacts.chartUnavailable") });
5203
+ return /* @__PURE__ */ jsxRuntime.jsx(WarningBox, { message: t("Artifacts.ChartUnavailable") });
5215
5204
  }
5216
5205
  if (isImageArtifact2(artifact)) {
5217
5206
  if (!artifact.url) {
5218
- return /* @__PURE__ */ jsxRuntime.jsx(WarningBox, { message: t("artifacts.imageUnavailable") });
5207
+ return /* @__PURE__ */ jsxRuntime.jsx(WarningBox, { message: t("Artifacts.ImageUnavailable") });
5219
5208
  }
5220
5209
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
5221
5210
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-xl border border-gray-200/80 bg-gray-50/50 dark:border-gray-700/60 dark:bg-gray-800/30", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -5232,7 +5221,7 @@ function SessionArtifactPreview({ artifact }) {
5232
5221
  }
5233
5222
  if (isPDFArtifact(artifact)) {
5234
5223
  if (!artifact.url) {
5235
- return /* @__PURE__ */ jsxRuntime.jsx(WarningBox, { message: t("artifacts.downloadUnavailable") });
5224
+ return /* @__PURE__ */ jsxRuntime.jsx(WarningBox, { message: t("Artifacts.DownloadUnavailable") });
5236
5225
  }
5237
5226
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
5238
5227
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-xl border border-gray-200/80 bg-gray-50 dark:border-gray-700/60 dark:bg-gray-900", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -5248,7 +5237,7 @@ function SessionArtifactPreview({ artifact }) {
5248
5237
  }
5249
5238
  if (isOfficeDocumentArtifact(artifact)) {
5250
5239
  if (!artifact.url) {
5251
- return /* @__PURE__ */ jsxRuntime.jsx(WarningBox, { message: t("artifacts.downloadUnavailable") });
5240
+ return /* @__PURE__ */ jsxRuntime.jsx(WarningBox, { message: t("Artifacts.DownloadUnavailable") });
5252
5241
  }
5253
5242
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
5254
5243
  officeViewerURL ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden rounded-xl border border-gray-200/80 bg-gray-50 dark:border-gray-700/60 dark:bg-gray-900", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -5258,7 +5247,7 @@ function SessionArtifactPreview({ artifact }) {
5258
5247
  title: artifact.name,
5259
5248
  className: "h-[72vh] w-full"
5260
5249
  }
5261
- ) }) : /* @__PURE__ */ jsxRuntime.jsx(WarningBox, { message: t("artifacts.officePreviewUnavailable") }),
5250
+ ) }) : /* @__PURE__ */ jsxRuntime.jsx(WarningBox, { message: t("Artifacts.OfficePreviewUnavailable") }),
5262
5251
  /* @__PURE__ */ jsxRuntime.jsx(ArtifactActions, { url: artifact.url })
5263
5252
  ] });
5264
5253
  }
@@ -5272,13 +5261,13 @@ function SessionArtifactPreview({ artifact }) {
5272
5261
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3", children: [
5273
5262
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-[240px] flex-col items-center justify-center rounded-xl border border-gray-200/80 bg-gray-50/60 p-6 text-center dark:border-gray-700/60 dark:bg-gray-900", children: [
5274
5263
  /* @__PURE__ */ jsxRuntime.jsx(react.FileText, { className: "h-8 w-8 text-gray-400 dark:text-gray-500", weight: "duotone" }),
5275
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-3 text-sm font-medium text-gray-800 dark:text-gray-100", children: t("artifacts.previewUnavailable") }),
5276
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-gray-500 dark:text-gray-400", children: t("artifacts.previewNotSupported") })
5264
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-3 text-sm font-medium text-gray-800 dark:text-gray-100", children: t("Artifacts.PreviewUnavailable") }),
5265
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-xs text-gray-500 dark:text-gray-400", children: t("Artifacts.PreviewNotSupported") })
5277
5266
  ] }),
5278
5267
  /* @__PURE__ */ jsxRuntime.jsx(ArtifactActions, { url: artifact.url })
5279
5268
  ] });
5280
5269
  }
5281
- return /* @__PURE__ */ jsxRuntime.jsx(WarningBox, { message: t("artifacts.downloadUnavailable") });
5270
+ return /* @__PURE__ */ jsxRuntime.jsx(WarningBox, { message: t("Artifacts.DownloadUnavailable") });
5282
5271
  }
5283
5272
  function SessionArtifactPreviewModal({
5284
5273
  isOpen,
@@ -5324,7 +5313,7 @@ function SessionArtifactPreviewModal({
5324
5313
  await onRename(artifact, nextName);
5325
5314
  setIsEditingName(false);
5326
5315
  } catch (err) {
5327
- setError(err instanceof Error ? err.message : t("artifacts.renameFailed"));
5316
+ setError(err instanceof Error ? err.message : t("Artifacts.RenameFailed"));
5328
5317
  } finally {
5329
5318
  setSubmittingRename(false);
5330
5319
  }
@@ -5333,7 +5322,7 @@ function SessionArtifactPreviewModal({
5333
5322
  if (!artifact || !onDelete) {
5334
5323
  return;
5335
5324
  }
5336
- if (!window.confirm(t("artifacts.deleteConfirm"))) {
5325
+ if (!window.confirm(t("Artifacts.DeleteConfirm"))) {
5337
5326
  return;
5338
5327
  }
5339
5328
  setSubmittingDelete(true);
@@ -5342,7 +5331,7 @@ function SessionArtifactPreviewModal({
5342
5331
  await onDelete(artifact);
5343
5332
  onClose();
5344
5333
  } catch (err) {
5345
- setError(err instanceof Error ? err.message : t("artifacts.deleteFailed"));
5334
+ setError(err instanceof Error ? err.message : t("Artifacts.DeleteFailed"));
5346
5335
  } finally {
5347
5336
  setSubmittingDelete(false);
5348
5337
  }
@@ -5373,7 +5362,7 @@ function SessionArtifactPreviewModal({
5373
5362
  }
5374
5363
  },
5375
5364
  className: "w-full rounded-lg border border-gray-300 px-3 py-1.5 text-sm text-gray-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 dark:border-gray-600 dark:bg-gray-800 dark:text-gray-100",
5376
- "aria-label": t("artifacts.rename"),
5365
+ "aria-label": t("Artifacts.Rename"),
5377
5366
  autoFocus: true
5378
5367
  }
5379
5368
  ),
@@ -5388,7 +5377,7 @@ function SessionArtifactPreviewModal({
5388
5377
  className: "cursor-pointer inline-flex items-center gap-1 rounded-lg bg-primary-600 px-2.5 py-1.5 text-xs font-medium text-white transition-colors hover:bg-primary-700 disabled:cursor-not-allowed disabled:opacity-60",
5389
5378
  children: [
5390
5379
  /* @__PURE__ */ jsxRuntime.jsx(react.FloppyDisk, { className: "h-3.5 w-3.5", weight: "bold" }),
5391
- t("message.save")
5380
+ t("Message.Save")
5392
5381
  ]
5393
5382
  }
5394
5383
  ),
@@ -5402,7 +5391,7 @@ function SessionArtifactPreviewModal({
5402
5391
  },
5403
5392
  disabled: submittingRename,
5404
5393
  className: "cursor-pointer rounded-lg border border-gray-200 px-2.5 py-1.5 text-xs font-medium text-gray-700 transition-colors hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-60 dark:border-gray-700 dark:text-gray-200 dark:hover:bg-gray-800",
5405
- children: t("message.cancel")
5394
+ children: t("Message.Cancel")
5406
5395
  }
5407
5396
  )
5408
5397
  ] }) : /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "truncate text-base font-semibold text-gray-900 dark:text-gray-100", children: artifact.name }),
@@ -5418,8 +5407,8 @@ function SessionArtifactPreviewModal({
5418
5407
  setIsEditingName(true);
5419
5408
  },
5420
5409
  className: "cursor-pointer rounded-lg border border-gray-200 p-2 text-gray-600 transition-colors hover:bg-gray-50 hover:text-gray-900 dark:border-gray-700 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-gray-100",
5421
- "aria-label": t("artifacts.rename"),
5422
- title: t("artifacts.rename"),
5410
+ "aria-label": t("Artifacts.Rename"),
5411
+ title: t("Artifacts.Rename"),
5423
5412
  children: /* @__PURE__ */ jsxRuntime.jsx(react.PencilSimple, { className: "h-4 w-4", weight: "regular" })
5424
5413
  }
5425
5414
  ),
@@ -5432,8 +5421,8 @@ function SessionArtifactPreviewModal({
5432
5421
  },
5433
5422
  disabled: submittingDelete,
5434
5423
  className: "cursor-pointer rounded-lg border border-red-200 p-2 text-red-600 transition-colors hover:bg-red-50 hover:text-red-700 disabled:cursor-not-allowed disabled:opacity-60 dark:border-red-900/60 dark:text-red-400 dark:hover:bg-red-950/30 dark:hover:text-red-300",
5435
- "aria-label": t("artifacts.delete"),
5436
- title: t("artifacts.delete"),
5424
+ "aria-label": t("Artifacts.Delete"),
5425
+ title: t("Artifacts.Delete"),
5437
5426
  children: /* @__PURE__ */ jsxRuntime.jsx(react.Trash, { className: "h-4 w-4", weight: "regular" })
5438
5427
  }
5439
5428
  ),
@@ -5443,8 +5432,8 @@ function SessionArtifactPreviewModal({
5443
5432
  type: "button",
5444
5433
  onClick: handleClose,
5445
5434
  className: "cursor-pointer rounded-lg border border-gray-200 p-2 text-gray-600 transition-colors hover:bg-gray-50 hover:text-gray-900 dark:border-gray-700 dark:text-gray-300 dark:hover:bg-gray-800 dark:hover:text-gray-100",
5446
- "aria-label": t("common.close"),
5447
- title: t("common.close"),
5435
+ "aria-label": t("Common.Close"),
5436
+ title: t("Common.Close"),
5448
5437
  children: /* @__PURE__ */ jsxRuntime.jsx(react.X, { className: "h-4 w-4", weight: "bold" })
5449
5438
  }
5450
5439
  )
@@ -5548,7 +5537,7 @@ function SessionArtifactsPanel({
5548
5537
  if (requestID !== requestSeq.current) {
5549
5538
  return;
5550
5539
  }
5551
- setError(err instanceof Error ? err.message : tRef.current("artifacts.failedToLoad"));
5540
+ setError(err instanceof Error ? err.message : tRef.current("Artifacts.FailedToLoad"));
5552
5541
  } finally {
5553
5542
  if (requestID === requestSeq.current) {
5554
5543
  setFetching(false);
@@ -5663,7 +5652,7 @@ function SessionArtifactsPanel({
5663
5652
  }
5664
5653
  setError(null);
5665
5654
  } catch (err) {
5666
- setError(err instanceof Error ? err.message : tRef.current("artifacts.failedToLoad"));
5655
+ setError(err instanceof Error ? err.message : tRef.current("Artifacts.FailedToLoad"));
5667
5656
  }
5668
5657
  }, [canDropFiles, dataSource, fetchArtifacts, hasDragFiles, sessionId, setDropSuccessState]);
5669
5658
  const canRenameArtifacts = typeof dataSource.renameSessionArtifact === "function";
@@ -5712,7 +5701,7 @@ function SessionArtifactsPanel({
5712
5701
  isDragging ? "bg-primary-50/40 dark:bg-primary-950/20" : "",
5713
5702
  className
5714
5703
  ].join(" "),
5715
- "aria-label": t("artifacts.title"),
5704
+ "aria-label": t("Artifacts.Title"),
5716
5705
  onDragEnter: handleDragEnter,
5717
5706
  onDragOver: handleDragOver,
5718
5707
  onDragLeave: handleDragLeave,
@@ -5727,18 +5716,18 @@ function SessionArtifactsPanel({
5727
5716
  ].join(" "),
5728
5717
  children: [
5729
5718
  /* @__PURE__ */ jsxRuntime.jsx(react.Paperclip, { className: "h-5 w-5", weight: "bold" }),
5730
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: dropSuccess ? t("input.filesAdded") : t("input.dropFiles") })
5719
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-medium", children: dropSuccess ? t("Input.FilesAdded") : t("Input.DropFiles") })
5731
5720
  ]
5732
5721
  }
5733
5722
  ) }),
5734
5723
  /* @__PURE__ */ jsxRuntime.jsx("header", { className: "flex items-center justify-between border-b border-gray-200 px-3 py-2 dark:border-gray-700/80", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "truncate text-sm font-semibold text-gray-900 dark:text-gray-100", children: [
5735
- t("artifacts.title"),
5724
+ t("Artifacts.Title"),
5736
5725
  " (",
5737
5726
  artifacts.length,
5738
5727
  ")"
5739
5728
  ] }) }) }),
5740
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-3 py-3", children: fetching ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center text-sm text-gray-500 dark:text-gray-400", children: t("artifacts.loading") }) : error ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3 rounded-lg border border-red-200 bg-red-50 p-3 dark:border-red-900/70 dark:bg-red-950/30", children: [
5741
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-red-800 dark:text-red-300", children: t("artifacts.failedToLoad") }),
5729
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-0 flex-1 overflow-y-auto px-3 py-3", children: fetching ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center text-sm text-gray-500 dark:text-gray-400", children: t("Artifacts.Loading") }) : error ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-3 rounded-lg border border-red-200 bg-red-50 p-3 dark:border-red-900/70 dark:bg-red-950/30", children: [
5730
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-red-800 dark:text-red-300", children: t("Artifacts.FailedToLoad") }),
5742
5731
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-red-700 dark:text-red-400", children: error }),
5743
5732
  /* @__PURE__ */ jsxRuntime.jsx(
5744
5733
  "button",
@@ -5748,10 +5737,10 @@ function SessionArtifactsPanel({
5748
5737
  void fetchArtifacts({ reset: true, manual: true });
5749
5738
  },
5750
5739
  className: "cursor-pointer rounded-md border border-red-300 px-2 py-1 text-xs font-medium text-red-700 hover:bg-red-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-red-400/50 dark:border-red-800 dark:text-red-300 dark:hover:bg-red-900/40",
5751
- children: t("alert.retry")
5740
+ children: t("Alert.Retry")
5752
5741
  }
5753
5742
  )
5754
- ] }) : !canFetchArtifacts ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-amber-200 bg-amber-50 p-3 text-sm text-amber-800 dark:border-amber-900/70 dark:bg-amber-950/30 dark:text-amber-200", children: t("artifacts.unsupported") }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5743
+ ] }) : !canFetchArtifacts ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg border border-amber-200 bg-amber-50 p-3 text-sm text-amber-800 dark:border-amber-900/70 dark:bg-amber-950/30 dark:text-amber-200", children: t("Artifacts.Unsupported") }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5755
5744
  /* @__PURE__ */ jsxRuntime.jsx(
5756
5745
  SessionArtifactList,
5757
5746
  {
@@ -5769,7 +5758,7 @@ function SessionArtifactsPanel({
5769
5758
  },
5770
5759
  disabled: loadingMore || refreshing || fetching,
5771
5760
  className: "cursor-pointer rounded-md border border-gray-200 px-3 py-1.5 text-xs font-medium text-gray-700 transition-colors hover:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-700 dark:text-gray-200 dark:hover:bg-gray-800",
5772
- children: loadingMore ? t("artifacts.loadingMore") : t("artifacts.loadMore")
5761
+ children: loadingMore ? t("Artifacts.LoadingMore") : t("Artifacts.LoadMore")
5773
5762
  }
5774
5763
  ) })
5775
5764
  ] }) }),
@@ -5810,25 +5799,17 @@ function ChatSessionCore({
5810
5799
  artifactsPanelStorageKey = "bichat.artifacts-panel.expanded"
5811
5800
  }) {
5812
5801
  const { t } = useTranslation();
5802
+ const { session, fetching, error, debugMode, sessionDebugUsage, debugLimits, currentSessionId } = useChatSession();
5803
+ const { turns, loading, isStreaming } = useChatMessaging();
5813
5804
  const {
5814
- session,
5815
- turns,
5816
- fetching,
5817
- error,
5818
5805
  inputError,
5819
5806
  message,
5820
5807
  setMessage,
5821
5808
  setInputError,
5822
- loading,
5823
5809
  handleSubmit,
5824
5810
  messageQueue,
5825
- handleUnqueue,
5826
- debugMode,
5827
- sessionDebugUsage,
5828
- debugLimits,
5829
- currentSessionId,
5830
- isStreaming
5831
- } = useChat();
5811
+ handleUnqueue
5812
+ } = useChatInput();
5832
5813
  const effectiveReadOnly = Boolean(readOnly ?? isReadOnly);
5833
5814
  const [artifactsPanelExpanded, setArtifactsPanelExpanded] = React.useState(
5834
5815
  artifactsPanelDefaultExpanded
@@ -5902,11 +5883,11 @@ function ChatSessionCore({
5902
5883
  };
5903
5884
  }, [isResizingArtifactsPanel, artifactsPanelStorageKey]);
5904
5885
  if (fetching) {
5905
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-500 dark:text-gray-400", children: t("input.processing") }) });
5886
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-gray-500 dark:text-gray-400", children: t("Input.Processing") }) });
5906
5887
  }
5907
5888
  if (error) {
5908
5889
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex h-full items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-red-500 dark:text-red-400", children: [
5909
- t("error.generic"),
5890
+ t("Error.Generic"),
5910
5891
  ": ",
5911
5892
  error
5912
5893
  ] }) });
@@ -5942,11 +5923,11 @@ function ChatSessionCore({
5942
5923
  "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50",
5943
5924
  artifactsPanelExpanded ? "bg-primary-50 text-primary-700 hover:bg-primary-100 dark:bg-primary-950/30 dark:text-primary-300 dark:hover:bg-primary-900/40" : "text-gray-500 hover:bg-gray-100 hover:text-gray-700 dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-200"
5944
5925
  ].join(" "),
5945
- "aria-label": artifactsPanelExpanded ? t("artifacts.toggleHide") : t("artifacts.toggleShow"),
5946
- title: artifactsPanelExpanded ? t("artifacts.toggleHide") : t("artifacts.toggleShow"),
5926
+ "aria-label": artifactsPanelExpanded ? t("Artifacts.ToggleHide") : t("Artifacts.ToggleShow"),
5927
+ title: artifactsPanelExpanded ? t("Artifacts.ToggleHide") : t("Artifacts.ToggleShow"),
5947
5928
  children: [
5948
5929
  /* @__PURE__ */ jsxRuntime.jsx(react.Sidebar, { className: "h-4 w-4", weight: artifactsPanelExpanded ? "duotone" : "regular" }),
5949
- t("artifacts.title")
5930
+ t("Artifacts.Title")
5950
5931
  ]
5951
5932
  }
5952
5933
  ),
@@ -5994,7 +5975,7 @@ function ChatSessionCore({
5994
5975
  formClassName: "mx-auto"
5995
5976
  }
5996
5977
  ),
5997
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-4 pb-1 text-center text-xs text-gray-500 dark:text-gray-400", children: t("welcome.disclaimer") })
5978
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-4 pb-1 text-center text-xs text-gray-500 dark:text-gray-400", children: t("Welcome.Disclaimer") })
5998
5979
  ] }) }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
5999
5980
  /* @__PURE__ */ jsxRuntime.jsx(
6000
5981
  MessageList,
@@ -6044,7 +6025,7 @@ function ChatSessionCore({
6044
6025
  "div",
6045
6026
  {
6046
6027
  role: "separator",
6047
- "aria-label": t("artifacts.resize"),
6028
+ "aria-label": t("Artifacts.Resize"),
6048
6029
  onMouseDown: handleArtifactsResizeStart,
6049
6030
  className: "relative flex shrink-0 cursor-col-resize touch-none items-center justify-center w-2 transition-colors lg:flex group/resize after:absolute after:inset-y-0 after:left-0 after:w-0.5 after:bg-gray-300 dark:after:bg-gray-600 after:transition-colors group-hover/resize:after:bg-primary-400 dark:group-hover/resize:after:bg-primary-500",
6050
6031
  children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute h-10 w-1.5 cursor-col-resize rounded-full bg-gray-400 transition-colors group-hover/resize:bg-primary-400 dark:bg-gray-500 dark:group-hover/resize:bg-primary-500" })
@@ -6085,7 +6066,7 @@ function ChatSessionCore({
6085
6066
  animate: { opacity: 1 },
6086
6067
  exit: { opacity: 0 },
6087
6068
  onClick: handleToggleArtifactsPanel,
6088
- "aria-label": t("common.close")
6069
+ "aria-label": t("Common.Close")
6089
6070
  }
6090
6071
  ),
6091
6072
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -6785,14 +6766,14 @@ MemoizedUserAvatar.displayName = "UserAvatar";
6785
6766
  function PermissionGuard({
6786
6767
  permissions,
6787
6768
  mode = "all",
6788
- hasPermission: hasPermission3,
6769
+ hasPermission: hasPermission2,
6789
6770
  fallback = null,
6790
6771
  children
6791
6772
  }) {
6792
6773
  if (permissions.length === 0) {
6793
6774
  return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
6794
6775
  }
6795
- const permitted = mode === "all" ? permissions.every((p) => hasPermission3(p)) : permissions.some((p) => hasPermission3(p));
6776
+ const permitted = mode === "all" ? permissions.every((p) => hasPermission2(p)) : permissions.some((p) => hasPermission2(p));
6796
6777
  return permitted ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children }) : /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback });
6797
6778
  }
6798
6779
  function DefaultErrorContent({
@@ -7097,8 +7078,8 @@ var SessionItem = React.memo(
7097
7078
  React.useEffect(() => {
7098
7079
  setIsTouch("ontouchend" in document);
7099
7080
  }, []);
7100
- const isTitleGenerating = !session.title || session.title === t("chat.newChat");
7101
- const displayTitle = isTitleGenerating ? t("common.generating") : session.title ?? t("common.untitled");
7081
+ const isTitleGenerating = !session.title || session.title === t("Chat.NewChat");
7082
+ const displayTitle = isTitleGenerating ? t("Common.Generating") : session.title ?? t("Common.Untitled");
7102
7083
  const { handlers: longPressHandlers } = useLongPress({
7103
7084
  delay: 500,
7104
7085
  onLongPress: (e) => {
@@ -7127,45 +7108,45 @@ var SessionItem = React.memo(
7127
7108
  const contextMenuItems = mode === "archived" ? [
7128
7109
  ...onRestore ? [{
7129
7110
  id: "restore",
7130
- label: t("archived.restoreButton"),
7111
+ label: t("Archived.RestoreButton"),
7131
7112
  icon: /* @__PURE__ */ jsxRuntime.jsx(react.ArrowUUpLeft, { size: 20 }),
7132
7113
  onClick: () => onRestore()
7133
7114
  }] : [],
7134
7115
  ...onRename ? [{
7135
7116
  id: "rename",
7136
- label: t("sidebar.renameChat"),
7117
+ label: t("Sidebar.RenameChat"),
7137
7118
  icon: /* @__PURE__ */ jsxRuntime.jsx(react.PencilSimple, { size: 20 }),
7138
7119
  onClick: () => editableTitleRef.current?.startEditing()
7139
7120
  }] : []
7140
7121
  ] : [
7141
7122
  ...onPin ? [{
7142
7123
  id: "pin",
7143
- label: session.pinned ? t("sidebar.unpinChat") : t("sidebar.pinChat"),
7124
+ label: session.pinned ? t("Sidebar.UnpinChat") : t("Sidebar.PinChat"),
7144
7125
  icon: session.pinned ? /* @__PURE__ */ jsxRuntime.jsx(react.Check, { size: 20 }) : /* @__PURE__ */ jsxRuntime.jsx(react.Bookmark, { size: 20 }),
7145
7126
  onClick: () => onPin()
7146
7127
  }] : [],
7147
7128
  ...onRename ? [{
7148
7129
  id: "rename",
7149
- label: t("sidebar.renameChat"),
7130
+ label: t("Sidebar.RenameChat"),
7150
7131
  icon: /* @__PURE__ */ jsxRuntime.jsx(react.PencilSimple, { size: 20 }),
7151
7132
  onClick: () => editableTitleRef.current?.startEditing()
7152
7133
  }] : [],
7153
7134
  ...onRegenerateTitle ? [{
7154
7135
  id: "regenerate",
7155
- label: t("sidebar.regenerateTitle"),
7136
+ label: t("Sidebar.RegenerateTitle"),
7156
7137
  icon: /* @__PURE__ */ jsxRuntime.jsx(react.ArrowsClockwise, { size: 20 }),
7157
7138
  onClick: () => onRegenerateTitle()
7158
7139
  }] : [],
7159
7140
  ...onArchive ? [{
7160
7141
  id: "archive",
7161
- label: t("sidebar.archiveChat"),
7142
+ label: t("Sidebar.ArchiveChat"),
7162
7143
  icon: /* @__PURE__ */ jsxRuntime.jsx(react.Archive, { size: 20 }),
7163
7144
  onClick: () => onArchive(),
7164
7145
  variant: "danger"
7165
7146
  }] : [],
7166
7147
  ...onDelete ? [{
7167
7148
  id: "delete",
7168
- label: t("sidebar.deleteChat"),
7149
+ label: t("Sidebar.DeleteChat"),
7169
7150
  icon: /* @__PURE__ */ jsxRuntime.jsx(react.Trash, { size: 20 }),
7170
7151
  onClick: () => onDelete(),
7171
7152
  variant: "danger"
@@ -7211,7 +7192,7 @@ var SessionItem = React.memo(
7211
7192
  e.stopPropagation();
7212
7193
  },
7213
7194
  className: "opacity-0 group-hover:opacity-100 p-1.5 rounded hover:bg-gray-200 dark:hover:bg-gray-700 transition-smooth flex-shrink-0 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50",
7214
- "aria-label": t("sidebar.chatOptions"),
7195
+ "aria-label": t("Sidebar.ChatOptions"),
7215
7196
  "data-testid": `${testIdPrefix}-session-options-${session.id}`,
7216
7197
  children: /* @__PURE__ */ jsxRuntime.jsx(react.DotsThree, { size: 16, className: "w-4 h-4", weight: "bold" })
7217
7198
  }
@@ -7231,11 +7212,11 @@ var SessionItem = React.memo(
7231
7212
  onPin();
7232
7213
  },
7233
7214
  className: `cursor-pointer flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 transition-smooth ${focus ? "bg-gray-100 dark:bg-gray-800/70 ring-1 ring-gray-200/80 dark:ring-gray-700/80" : "hover:bg-gray-50 dark:hover:bg-gray-800"}`,
7234
- "aria-label": session.pinned ? t("sidebar.unpinChat") : t("sidebar.pinChat"),
7215
+ "aria-label": session.pinned ? t("Sidebar.UnpinChat") : t("Sidebar.PinChat"),
7235
7216
  "data-testid": `${testIdPrefix}-session-pin-${session.id}`,
7236
7217
  children: [
7237
7218
  session.pinned ? /* @__PURE__ */ jsxRuntime.jsx(react.Check, { size: 16, className: "w-4 h-4" }) : /* @__PURE__ */ jsxRuntime.jsx(react.Bookmark, { size: 16, className: "w-4 h-4" }),
7238
- session.pinned ? t("sidebar.unpinChat") : t("sidebar.pinChat")
7219
+ session.pinned ? t("Sidebar.UnpinChat") : t("Sidebar.PinChat")
7239
7220
  ]
7240
7221
  }
7241
7222
  ) }),
@@ -7249,11 +7230,11 @@ var SessionItem = React.memo(
7249
7230
  close();
7250
7231
  },
7251
7232
  className: `cursor-pointer flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 transition-smooth ${focus ? "bg-gray-100 dark:bg-gray-800/70 ring-1 ring-gray-200/80 dark:ring-gray-700/80" : "hover:bg-gray-50 dark:hover:bg-gray-800"}`,
7252
- "aria-label": t("sidebar.renameChat"),
7233
+ "aria-label": t("Sidebar.RenameChat"),
7253
7234
  "data-testid": `${testIdPrefix}-session-rename-${session.id}`,
7254
7235
  children: [
7255
7236
  /* @__PURE__ */ jsxRuntime.jsx(react.PencilSimple, { size: 16, className: "w-4 h-4" }),
7256
- t("sidebar.renameChat")
7237
+ t("Sidebar.RenameChat")
7257
7238
  ]
7258
7239
  }
7259
7240
  ) }),
@@ -7267,11 +7248,11 @@ var SessionItem = React.memo(
7267
7248
  close();
7268
7249
  },
7269
7250
  className: `cursor-pointer flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium text-gray-700 dark:text-gray-200 transition-smooth ${focus ? "bg-gray-100 dark:bg-gray-800/70 ring-1 ring-gray-200/80 dark:ring-gray-700/80" : "hover:bg-gray-50 dark:hover:bg-gray-800"}`,
7270
- "aria-label": t("sidebar.regenerateTitle"),
7251
+ "aria-label": t("Sidebar.RegenerateTitle"),
7271
7252
  "data-testid": `${testIdPrefix}-session-regenerate-${session.id}`,
7272
7253
  children: [
7273
7254
  /* @__PURE__ */ jsxRuntime.jsx(react.ArrowsClockwise, { size: 16, className: "w-4 h-4" }),
7274
- t("sidebar.regenerateTitle")
7255
+ t("Sidebar.RegenerateTitle")
7275
7256
  ]
7276
7257
  }
7277
7258
  ) }),
@@ -7284,11 +7265,11 @@ var SessionItem = React.memo(
7284
7265
  onRestore();
7285
7266
  },
7286
7267
  className: `cursor-pointer flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium transition-smooth ${focus ? "text-green-700 dark:text-green-300 bg-green-50 dark:bg-green-900/20 ring-1 ring-green-200/70 dark:ring-green-500/30" : "text-green-700 dark:text-green-300 hover:bg-green-50/70 dark:hover:bg-green-900/10"}`,
7287
- "aria-label": t("archived.restoreButton"),
7268
+ "aria-label": t("Archived.RestoreButton"),
7288
7269
  "data-testid": `${testIdPrefix}-session-restore-${session.id}`,
7289
7270
  children: [
7290
7271
  /* @__PURE__ */ jsxRuntime.jsx(react.ArrowUUpLeft, { size: 16, className: "w-4 h-4" }),
7291
- t("archived.restoreButton")
7272
+ t("Archived.RestoreButton")
7292
7273
  ]
7293
7274
  }
7294
7275
  ) }),
@@ -7301,11 +7282,11 @@ var SessionItem = React.memo(
7301
7282
  onArchive();
7302
7283
  },
7303
7284
  className: `cursor-pointer flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium transition-smooth ${focus ? "text-amber-600 dark:text-amber-400 bg-amber-50 dark:bg-amber-900/20 ring-1 ring-amber-200/70 dark:ring-amber-500/30" : "text-amber-600 dark:text-amber-400 hover:bg-amber-50/70 dark:hover:bg-amber-900/10"}`,
7304
- "aria-label": t("sidebar.archiveChat"),
7285
+ "aria-label": t("Sidebar.ArchiveChat"),
7305
7286
  "data-testid": `${testIdPrefix}-session-archive-${session.id}`,
7306
7287
  children: [
7307
7288
  /* @__PURE__ */ jsxRuntime.jsx(react.Archive, { size: 16, className: "w-4 h-4" }),
7308
- t("sidebar.archiveChat")
7289
+ t("Sidebar.ArchiveChat")
7309
7290
  ]
7310
7291
  }
7311
7292
  ) }),
@@ -7318,11 +7299,11 @@ var SessionItem = React.memo(
7318
7299
  onDelete();
7319
7300
  },
7320
7301
  className: `cursor-pointer flex w-full items-center gap-2 rounded-lg px-3 py-2 text-sm font-medium transition-smooth ${focus ? "text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900/20 ring-1 ring-red-200/70 dark:ring-red-500/30" : "text-red-600 dark:text-red-400 hover:bg-red-50/70 dark:hover:bg-red-900/10"}`,
7321
- "aria-label": t("sidebar.deleteChat"),
7302
+ "aria-label": t("Sidebar.DeleteChat"),
7322
7303
  "data-testid": `${testIdPrefix}-session-delete-${session.id}`,
7323
7304
  children: [
7324
7305
  /* @__PURE__ */ jsxRuntime.jsx(react.Trash, { size: 16, className: "w-4 h-4" }),
7325
- t("sidebar.deleteChat")
7306
+ t("Sidebar.DeleteChat")
7326
7307
  ]
7327
7308
  }
7328
7309
  ) })
@@ -7491,7 +7472,7 @@ function UserFilter({ users, selectedUser, onUserChange, loading }) {
7491
7472
  onUserChange(null);
7492
7473
  },
7493
7474
  className: "cursor-pointer p-1 rounded hover:bg-gray-200 dark:hover:bg-gray-600 transition-smooth",
7494
- "aria-label": t("common.clear"),
7475
+ "aria-label": t("Common.Clear"),
7495
7476
  children: /* @__PURE__ */ jsxRuntime.jsx(react.X, { size: 14, className: "w-3.5 h-3.5 text-gray-600 dark:text-gray-400" })
7496
7477
  }
7497
7478
  ),
@@ -7736,7 +7717,7 @@ function AllChatsList({ dataSource, onSessionSelect, activeSessionId }) {
7736
7717
  }
7737
7718
  ),
7738
7719
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
7739
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium truncate", children: chat.title || t("common.untitled") }),
7720
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium truncate", children: chat.title || t("Common.Untitled") }),
7740
7721
  /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-gray-500 dark:text-gray-400 truncate", children: [
7741
7722
  chat.owner.firstName,
7742
7723
  " ",
@@ -7744,7 +7725,7 @@ function AllChatsList({ dataSource, onSessionSelect, activeSessionId }) {
7744
7725
  ] }),
7745
7726
  chat.status === "archived" && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 mt-1 px-2 py-0.5 bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 rounded-full text-xs", children: [
7746
7727
  /* @__PURE__ */ jsxRuntime.jsx(react.Archive, { size: 12, className: "w-3 h-3" }),
7747
- t("chat.archived")
7728
+ t("Chat.Archived")
7748
7729
  ] })
7749
7730
  ] })
7750
7731
  ] })
@@ -7811,11 +7792,11 @@ function groupSessionsByDate(sessions, t) {
7811
7792
  const today = dateFns.startOfDay(now);
7812
7793
  const translate = t || ((key2) => key2);
7813
7794
  const dateLabels = {
7814
- "Today": translate("dateGroup.today"),
7815
- "Yesterday": translate("dateGroup.yesterday"),
7816
- "Last 7 Days": translate("dateGroup.last7Days"),
7817
- "Last 30 Days": translate("dateGroup.last30Days"),
7818
- "Older": translate("dateGroup.older")
7795
+ "Today": translate("DateGroup.Today"),
7796
+ "Yesterday": translate("DateGroup.Yesterday"),
7797
+ "Last 7 Days": translate("DateGroup.Last7Days"),
7798
+ "Last 30 Days": translate("DateGroup.Last30Days"),
7799
+ "Older": translate("DateGroup.Older")
7819
7800
  };
7820
7801
  const groupMap = /* @__PURE__ */ new Map([
7821
7802
  ["Today", []],
@@ -7879,9 +7860,9 @@ function Sidebar2({
7879
7860
  const [showConfirm, setShowConfirm] = React.useState(false);
7880
7861
  const [sessionToArchive, setSessionToArchive] = React.useState(null);
7881
7862
  const tabs = React.useMemo(() => {
7882
- const items = [{ id: "my-chats", label: t("sidebar.myChats") }];
7863
+ const items = [{ id: "my-chats", label: t("Sidebar.MyChats") }];
7883
7864
  if (showAllChatsTab) {
7884
- items.push({ id: "all-chats", label: t("sidebar.allChats") });
7865
+ items.push({ id: "all-chats", label: t("Sidebar.AllChats") });
7885
7866
  }
7886
7867
  return items;
7887
7868
  }, [showAllChatsTab, t]);
@@ -7893,7 +7874,7 @@ function Sidebar2({
7893
7874
  setSessions(result.sessions);
7894
7875
  } catch (err) {
7895
7876
  console.error("Failed to load sessions:", err);
7896
- setError(t("sidebar.failedToLoadSessions"));
7877
+ setError(t("Sidebar.FailedToLoadSessions"));
7897
7878
  } finally {
7898
7879
  setLoading(false);
7899
7880
  }
@@ -7901,11 +7882,9 @@ function Sidebar2({
7901
7882
  React.useEffect(() => {
7902
7883
  fetchSessions();
7903
7884
  }, [fetchSessions, refreshKey]);
7904
- const sessionsRef = React.useRef(sessions);
7905
- sessionsRef.current = sessions;
7906
7885
  const hasPlaceholderTitles = React.useMemo(() => {
7907
- const newChatLabel = t("chat.newChat");
7908
- return sessions.some((s) => s && (!s.title || s.title === newChatLabel));
7886
+ const newChatLabel = t("Chat.NewChat");
7887
+ return Array.isArray(sessions) && sessions.some((s) => s && (!s.title || s.title === newChatLabel));
7909
7888
  }, [sessions, t]);
7910
7889
  React.useEffect(() => {
7911
7890
  if (!hasPlaceholderTitles) return;
@@ -7918,8 +7897,6 @@ function Sidebar2({
7918
7897
  const result = await dataSource.listSessions({ limit: 50 });
7919
7898
  setSessions(result.sessions);
7920
7899
  } catch {
7921
- clearInterval(intervalId);
7922
- return;
7923
7900
  }
7924
7901
  if (pollCount >= maxPolls) {
7925
7902
  clearInterval(intervalId);
@@ -7942,7 +7919,7 @@ function Sidebar2({
7942
7919
  }
7943
7920
  } catch (err) {
7944
7921
  console.error("Failed to archive session:", err);
7945
- toast.error(t("sidebar.failedToArchiveChat"));
7922
+ toast.error(t("Sidebar.FailedToArchiveChat"));
7946
7923
  } finally {
7947
7924
  setShowConfirm(false);
7948
7925
  setSessionToArchive(null);
@@ -7958,27 +7935,27 @@ function Sidebar2({
7958
7935
  setRefreshKey((k) => k + 1);
7959
7936
  } catch (err) {
7960
7937
  console.error("Failed to toggle pin:", err);
7961
- toast.error(t("sidebar.failedToTogglePin"));
7938
+ toast.error(t("Sidebar.FailedToTogglePin"));
7962
7939
  }
7963
7940
  };
7964
7941
  const handleRenameSession = async (sessionId, newTitle) => {
7965
7942
  try {
7966
7943
  await dataSource.renameSession(sessionId, newTitle);
7967
- toast.success(t("sidebar.chatRenamedSuccessfully"));
7944
+ toast.success(t("Sidebar.ChatRenamedSuccessfully"));
7968
7945
  setRefreshKey((k) => k + 1);
7969
7946
  } catch (err) {
7970
7947
  console.error("Failed to update session title:", err);
7971
- toast.error(t("sidebar.failedToRenameChat"));
7948
+ toast.error(t("Sidebar.FailedToRenameChat"));
7972
7949
  }
7973
7950
  };
7974
7951
  const handleRegenerateTitle = async (sessionId) => {
7975
7952
  try {
7976
7953
  await dataSource.regenerateSessionTitle(sessionId);
7977
- toast.success(t("sidebar.titleRegenerated"));
7954
+ toast.success(t("Sidebar.TitleRegenerated"));
7978
7955
  setRefreshKey((k) => k + 1);
7979
7956
  } catch (err) {
7980
7957
  console.error("Failed to regenerate title:", err);
7981
- toast.error(t("sidebar.failedToRegenerateTitle"));
7958
+ toast.error(t("Sidebar.FailedToRegenerateTitle"));
7982
7959
  }
7983
7960
  };
7984
7961
  const filteredSessions = React.useMemo(() => {
@@ -8043,7 +8020,7 @@ function Sidebar2({
8043
8020
  {
8044
8021
  className: `w-64 bg-surface-300 dark:bg-gray-900 border-r border-gray-200 dark:border-gray-700 h-full min-h-0 flex flex-col overflow-hidden ${className}`,
8045
8022
  role: "navigation",
8046
- "aria-label": t("sidebar.chatSessions"),
8023
+ "aria-label": t("Sidebar.ChatSessions"),
8047
8024
  children: [
8048
8025
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 border-b border-gray-200 dark:border-gray-700 flex items-center justify-between", children: [
8049
8026
  headerSlot,
@@ -8052,8 +8029,8 @@ function Sidebar2({
8052
8029
  {
8053
8030
  onClick: onClose,
8054
8031
  className: "cursor-pointer p-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-800 transition-smooth text-gray-600 dark:text-gray-400",
8055
- title: t("sidebar.closeSidebar"),
8056
- "aria-label": t("sidebar.closeSidebar"),
8032
+ title: t("Sidebar.CloseSidebar"),
8033
+ "aria-label": t("Sidebar.CloseSidebar"),
8057
8034
  whileHover: "hover",
8058
8035
  whileTap: "tap",
8059
8036
  variants: buttonVariants,
@@ -8082,7 +8059,7 @@ function Sidebar2({
8082
8059
  {
8083
8060
  value: searchQuery,
8084
8061
  onChange: setSearchQuery,
8085
- placeholder: t("sidebar.searchChats")
8062
+ placeholder: t("Sidebar.SearchChats")
8086
8063
  }
8087
8064
  ) }),
8088
8065
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -8091,13 +8068,13 @@ function Sidebar2({
8091
8068
  onClick: onNewChat,
8092
8069
  disabled: creating || loading,
8093
8070
  className: "cursor-pointer w-full px-4 py-3 bg-primary-600 dark:bg-primary-700 text-white rounded-lg hover:bg-primary-700 dark:hover:bg-primary-800 transition-smooth font-medium disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center",
8094
- title: t("chat.newChat"),
8095
- "aria-label": t("sidebar.createNewChat"),
8071
+ title: t("Chat.NewChat"),
8072
+ "aria-label": t("Sidebar.CreateNewChat"),
8096
8073
  whileHover: shouldReduceMotion ? {} : { scale: 1.02 },
8097
8074
  whileTap: shouldReduceMotion ? {} : { scale: 0.95 },
8098
8075
  children: creating ? /* @__PURE__ */ jsxRuntime.jsx(LoadingSpinner_default, { variant: "spinner", size: "sm" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
8099
8076
  /* @__PURE__ */ jsxRuntime.jsx(react.Plus, { size: 20, className: "w-5 h-5" }),
8100
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: t("chat.newChat") })
8077
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: t("Chat.NewChat") })
8101
8078
  ] })
8102
8079
  }
8103
8080
  ) }),
@@ -8106,10 +8083,10 @@ function Sidebar2({
8106
8083
  {
8107
8084
  onClick: onArchivedView,
8108
8085
  className: "cursor-pointer flex items-center gap-2 px-3 py-2 rounded-lg text-gray-700 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-800 transition-smooth text-sm font-medium w-full",
8109
- title: t("sidebar.archivedChats"),
8086
+ title: t("Sidebar.ArchivedChats"),
8110
8087
  children: [
8111
8088
  /* @__PURE__ */ jsxRuntime.jsx(react.Archive, { size: 18, className: "w-4.5 h-4.5" }),
8112
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("sidebar.archivedChats") })
8089
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("Sidebar.ArchivedChats") })
8113
8090
  ]
8114
8091
  }
8115
8092
  ) }),
@@ -8126,7 +8103,7 @@ function Sidebar2({
8126
8103
  /* @__PURE__ */ jsxRuntime.jsx(
8127
8104
  DateGroupHeader,
8128
8105
  {
8129
- groupName: t("common.pinned"),
8106
+ groupName: t("Common.Pinned"),
8130
8107
  count: pinnedSessions.length
8131
8108
  }
8132
8109
  ),
@@ -8138,7 +8115,7 @@ function Sidebar2({
8138
8115
  initial: "hidden",
8139
8116
  animate: "visible",
8140
8117
  role: "list",
8141
- "aria-label": t("sidebar.pinnedChats"),
8118
+ "aria-label": t("Sidebar.PinnedChats"),
8142
8119
  children: pinnedSessions.map((session) => /* @__PURE__ */ jsxRuntime.jsx(
8143
8120
  SessionItem_default,
8144
8121
  {
@@ -8192,14 +8169,14 @@ function Sidebar2({
8192
8169
  filteredSessions.length === 0 && !loading && /* @__PURE__ */ jsxRuntime.jsx(
8193
8170
  MemoizedEmptyState,
8194
8171
  {
8195
- title: searchQuery ? t("sidebar.noChatsFound", { query: searchQuery }) : t("sidebar.noChatsYet"),
8196
- description: searchQuery ? void 0 : t("sidebar.createOneToGetStarted"),
8172
+ title: searchQuery ? t("Sidebar.NoChatsFound", { query: searchQuery }) : t("Sidebar.NoChatsYet"),
8173
+ description: searchQuery ? void 0 : t("Sidebar.CreateOneToGetStarted"),
8197
8174
  action: searchQuery ? /* @__PURE__ */ jsxRuntime.jsx(
8198
8175
  "button",
8199
8176
  {
8200
8177
  onClick: () => setSearchQuery(""),
8201
8178
  className: "cursor-pointer text-sm text-primary-600 dark:text-primary-400 hover:underline",
8202
- children: t("common.clear")
8179
+ children: t("Common.Clear")
8203
8180
  }
8204
8181
  ) : void 0
8205
8182
  }
@@ -8218,10 +8195,10 @@ function Sidebar2({
8218
8195
  ConfirmModal_default,
8219
8196
  {
8220
8197
  isOpen: showConfirm,
8221
- title: t("sidebar.archiveChatSession"),
8222
- message: t("sidebar.archiveChatMessage"),
8223
- confirmText: t("sidebar.archiveButton"),
8224
- cancelText: t("common.cancel"),
8198
+ title: t("Sidebar.ArchiveChatSession"),
8199
+ message: t("Sidebar.ArchiveChatMessage"),
8200
+ confirmText: t("Sidebar.ArchiveButton"),
8201
+ cancelText: t("Common.Cancel"),
8225
8202
  isDanger: false,
8226
8203
  onConfirm: confirmArchive,
8227
8204
  onCancel: () => {
@@ -8278,10 +8255,10 @@ function ArchivedChatList({
8278
8255
  try {
8279
8256
  await dataSource.unarchiveSession(sessionToRestore);
8280
8257
  setRefreshKey((k) => k + 1);
8281
- toast.success(t("archived.chatRestoredSuccessfully"));
8258
+ toast.success(t("Archived.ChatRestoredSuccessfully"));
8282
8259
  } catch (err) {
8283
8260
  console.error("Failed to restore session:", err);
8284
- toast.error(t("archived.failedToRestoreChat"));
8261
+ toast.error(t("Archived.FailedToRestoreChat"));
8285
8262
  } finally {
8286
8263
  setShowConfirm(false);
8287
8264
  setSessionToRestore(null);
@@ -8290,11 +8267,11 @@ function ArchivedChatList({
8290
8267
  const handleRenameSession = async (sessionId, newTitle) => {
8291
8268
  try {
8292
8269
  await dataSource.renameSession(sessionId, newTitle);
8293
- toast.success(t("sidebar.chatRenamedSuccessfully"));
8270
+ toast.success(t("Sidebar.ChatRenamedSuccessfully"));
8294
8271
  setRefreshKey((k) => k + 1);
8295
8272
  } catch (err) {
8296
8273
  console.error("Failed to update session title:", err);
8297
- toast.error(t("sidebar.failedToRenameChat"));
8274
+ toast.error(t("Sidebar.FailedToRenameChat"));
8298
8275
  }
8299
8276
  };
8300
8277
  const filteredSessions = React.useMemo(() => {
@@ -8322,10 +8299,10 @@ function ArchivedChatList({
8322
8299
  {
8323
8300
  onClick: onBack,
8324
8301
  className: "inline-flex items-center gap-2 px-3 py-2 rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors text-gray-600 dark:text-gray-400",
8325
- "aria-label": t("archived.backToChats"),
8302
+ "aria-label": t("Archived.BackToChats"),
8326
8303
  children: [
8327
8304
  /* @__PURE__ */ jsxRuntime.jsx(react.ArrowLeft, { size: 20, className: "w-5 h-5" }),
8328
- t("common.back")
8305
+ t("Common.Back")
8329
8306
  ]
8330
8307
  }
8331
8308
  ) }),
@@ -8337,14 +8314,14 @@ function ArchivedChatList({
8337
8314
  className: "w-6 h-6 text-gray-600 dark:text-gray-400"
8338
8315
  }
8339
8316
  ),
8340
- /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-bold text-gray-900 dark:text-white", children: t("archived.title") })
8317
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl font-bold text-gray-900 dark:text-white", children: t("Archived.Title") })
8341
8318
  ] }),
8342
8319
  /* @__PURE__ */ jsxRuntime.jsx(
8343
8320
  SearchInput_default,
8344
8321
  {
8345
8322
  value: searchQuery,
8346
8323
  onChange: setSearchQuery,
8347
- placeholder: t("archived.searchArchivedChats")
8324
+ placeholder: t("Archived.SearchArchivedChats")
8348
8325
  }
8349
8326
  )
8350
8327
  ] }),
@@ -8358,8 +8335,8 @@ function ArchivedChatList({
8358
8335
  className: "text-gray-400 dark:text-gray-500"
8359
8336
  }
8360
8337
  ),
8361
- title: t("archived.noArchivedChats"),
8362
- description: t("archived.noArchivedChatsDescription")
8338
+ title: t("Archived.NoArchivedChats"),
8339
+ description: t("Archived.NoArchivedChatsDescription")
8363
8340
  }
8364
8341
  ) }) : isEmptyAfterSearch ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center h-full px-6", children: /* @__PURE__ */ jsxRuntime.jsx(
8365
8342
  MemoizedEmptyState,
@@ -8371,8 +8348,8 @@ function ArchivedChatList({
8371
8348
  className: "text-gray-400 dark:text-gray-500"
8372
8349
  }
8373
8350
  ),
8374
- title: t("archived.noResults"),
8375
- description: t("archived.noResultsDescription", {
8351
+ title: t("Archived.NoResults"),
8352
+ description: t("Archived.NoResultsDescription", {
8376
8353
  query: searchQuery
8377
8354
  })
8378
8355
  }
@@ -8410,10 +8387,10 @@ function ArchivedChatList({
8410
8387
  ConfirmModal_default,
8411
8388
  {
8412
8389
  isOpen: showConfirm,
8413
- title: t("archived.restoreChat"),
8414
- message: t("archived.restoreChatMessage"),
8415
- confirmText: t("archived.restoreButton"),
8416
- cancelText: t("common.cancel"),
8390
+ title: t("Archived.RestoreChat"),
8391
+ message: t("Archived.RestoreChatMessage"),
8392
+ confirmText: t("Archived.RestoreButton"),
8393
+ cancelText: t("Common.Cancel"),
8417
8394
  isDanger: false,
8418
8395
  onConfirm: confirmRestore,
8419
8396
  onCancel: () => {
@@ -8499,7 +8476,7 @@ function Alert({
8499
8476
  {
8500
8477
  onClick: onRetry,
8501
8478
  className: `mt-2 text-xs px-3 py-1.5 rounded ${styles.retryButton} transition-colors font-medium`,
8502
- children: t("chat.retry")
8479
+ children: t("Chat.Retry")
8503
8480
  }
8504
8481
  )
8505
8482
  ] })
@@ -8509,7 +8486,7 @@ function Alert({
8509
8486
  {
8510
8487
  onClick: onDismiss,
8511
8488
  className: `${styles.button} transition-colors flex-shrink-0`,
8512
- "aria-label": t("chat.dismissNotification"),
8489
+ "aria-label": t("Chat.DismissNotification"),
8513
8490
  children: /* @__PURE__ */ jsxRuntime.jsx(react.X, { size: 20, className: "w-5 h-5" })
8514
8491
  }
8515
8492
  )
@@ -8616,17 +8593,17 @@ var RetryActionArea = React.memo(function RetryActionArea2({
8616
8593
  weight: "fill"
8617
8594
  }
8618
8595
  ),
8619
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-700 dark:text-gray-300", children: t("retry.description") })
8596
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm text-gray-700 dark:text-gray-300", children: t("Retry.Description") })
8620
8597
  ] }),
8621
8598
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-2", children: /* @__PURE__ */ jsxRuntime.jsxs(
8622
8599
  "button",
8623
8600
  {
8624
8601
  onClick: onRetry,
8625
8602
  className: "cursor-pointer inline-flex items-center gap-1.5 px-4 py-2 text-sm font-medium text-white bg-primary-600 hover:bg-primary-700 dark:bg-primary-700 dark:hover:bg-primary-600 rounded-lg transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-gray-800",
8626
- "aria-label": t("retry.title"),
8603
+ "aria-label": t("Retry.Title"),
8627
8604
  children: [
8628
8605
  /* @__PURE__ */ jsxRuntime.jsx(react.ArrowClockwise, { size: 16, className: "w-4 h-4" }),
8629
- t("retry.button")
8606
+ t("Retry.Button")
8630
8607
  ]
8631
8608
  }
8632
8609
  ) })
@@ -8664,7 +8641,7 @@ function StreamError({
8664
8641
  }
8665
8642
  ),
8666
8643
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [
8667
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-red-800 dark:text-red-200", children: t("error.generic") }),
8644
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium text-red-800 dark:text-red-200", children: t("Error.Generic") }),
8668
8645
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-red-600 dark:text-red-300 break-words", children: error })
8669
8646
  ] }),
8670
8647
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 flex-shrink-0", children: [
@@ -8860,7 +8837,7 @@ var AttachmentUpload = React.memo(
8860
8837
  setIsLoading(true);
8861
8838
  try {
8862
8839
  if (files.length > maxAttachments) {
8863
- toast.error(t("error.maxFiles", { max: maxAttachments, selected: files.length }));
8840
+ toast.error(t("Error.MaxFiles", { max: maxAttachments, selected: files.length }));
8864
8841
  setIsLoading(false);
8865
8842
  return;
8866
8843
  }
@@ -8876,7 +8853,7 @@ var AttachmentUpload = React.memo(
8876
8853
  try {
8877
8854
  const base64Data = await convertToBase64(file);
8878
8855
  const attachment = {
8879
- id: "",
8856
+ clientKey: crypto.randomUUID(),
8880
8857
  filename: file.name,
8881
8858
  mimeType: file.type,
8882
8859
  sizeBytes: file.size,
@@ -8900,10 +8877,10 @@ var AttachmentUpload = React.memo(
8900
8877
  }
8901
8878
  if (attachments.length > 0) {
8902
8879
  onAttachmentsSelected(attachments);
8903
- const message = attachments.length === 1 ? t("attachment.fileAdded", { size: formatFileSize(attachments[0].sizeBytes) }) : t("attachment.fileAdded", { size: `${attachments.length} files` });
8880
+ const message = attachments.length === 1 ? t("Attachment.FileAdded", { size: formatFileSize(attachments[0].sizeBytes) }) : t("Attachment.FileAdded", { size: `${attachments.length} files` });
8904
8881
  toast.success(message);
8905
8882
  } else if (errors.length > 0) {
8906
- toast.error(t("attachment.invalidFile"));
8883
+ toast.error(t("Attachment.InvalidFile"));
8907
8884
  }
8908
8885
  } finally {
8909
8886
  setIsLoading(false);
@@ -8926,7 +8903,7 @@ var AttachmentUpload = React.memo(
8926
8903
  onChange: handleFileSelect,
8927
8904
  disabled: isDisabled,
8928
8905
  className: "sr-only",
8929
- "aria-label": t("attachment.selectFiles")
8906
+ "aria-label": t("Attachment.SelectFiles")
8930
8907
  }
8931
8908
  ),
8932
8909
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -8936,7 +8913,7 @@ var AttachmentUpload = React.memo(
8936
8913
  onClick: handleClick,
8937
8914
  disabled: isDisabled,
8938
8915
  className: "\n flex items-center justify-center\n w-8 h-8\n text-gray-600 dark:text-gray-400\n hover:text-gray-800 dark:hover:text-gray-200\n hover:bg-gray-100 dark:hover:bg-gray-700\n disabled:text-gray-400 dark:disabled:text-gray-600\n disabled:opacity-50 disabled:cursor-not-allowed\n rounded-lg\n transition-all\n duration-200\n active:scale-95\n focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-500/50\n ",
8939
- "aria-label": t("attachment.selectFiles"),
8916
+ "aria-label": t("Attachment.SelectFiles"),
8940
8917
  "aria-busy": isLoading,
8941
8918
  children: isLoading ? /* @__PURE__ */ jsxRuntime.jsx(react.CircleNotch, { size: 20, className: "w-5 h-5 animate-spin", weight: "fill" }) : /* @__PURE__ */ jsxRuntime.jsx(react.Paperclip, { size: 20, className: "w-5 h-5", weight: "fill" })
8942
8919
  }
@@ -9024,7 +9001,7 @@ function QuestionStep({
9024
9001
  };
9025
9002
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
9026
9003
  /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-lg font-semibold text-gray-900 dark:text-white mb-2", children: question.text }) }),
9027
- isMultiSelect && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 dark:text-gray-500 italic", children: t("question.selectMulti") }),
9004
+ isMultiSelect && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-gray-500 dark:text-gray-500 italic", children: t("Question.SelectMulti") }),
9028
9005
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-3 sm:grid-cols-2", children: (question.options || []).map((option) => {
9029
9006
  const isSelected = selectedOptions.includes(option.label);
9030
9007
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -9064,7 +9041,7 @@ function QuestionStep({
9064
9041
  }) }),
9065
9042
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
9066
9043
  /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: "other-input", className: "block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2", children: [
9067
- t("question.specifyOther"),
9044
+ t("Question.SpecifyOther"),
9068
9045
  ":"
9069
9046
  ] }),
9070
9047
  /* @__PURE__ */ jsxRuntime.jsx(
@@ -9073,7 +9050,7 @@ function QuestionStep({
9073
9050
  id: "other-input",
9074
9051
  value: otherText,
9075
9052
  onChange: (e) => handleOtherTextChange(e.target.value),
9076
- placeholder: t("question.other"),
9053
+ placeholder: t("Question.Other"),
9077
9054
  rows: 3,
9078
9055
  className: "w-full px-4 py-3 border-2 border-gray-200 dark:border-gray-700 rounded-lg\n bg-white dark:bg-gray-800 text-gray-900 dark:text-white\n placeholder-gray-400 dark:placeholder-gray-500\n focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-primary-500\n resize-none"
9079
9056
  }
@@ -9116,7 +9093,7 @@ function ConfirmationStep({
9116
9093
  )),
9117
9094
  customText && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center px-3 py-1 rounded-lg text-sm font-medium border border-amber-500 bg-amber-500/10 text-amber-600 dark:border-amber-400 dark:bg-amber-400/10 dark:text-amber-400", children: [
9118
9095
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold mr-1", children: [
9119
- t("question.other"),
9096
+ t("Question.Other"),
9120
9097
  ":"
9121
9098
  ] }),
9122
9099
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "italic", children: customText })
@@ -9138,12 +9115,12 @@ function isQuestionAnswered(data) {
9138
9115
  function validateAnswers(questions, answers, t) {
9139
9116
  const allAnswered = questions.every((q) => isQuestionAnswered(answers[q.id]));
9140
9117
  if (!allAnswered) {
9141
- return t ? t("error.allQuestionsRequired") : "Please answer all questions before submitting";
9118
+ return t ? t("Error.AllQuestionsRequired") : "Please answer all questions before submitting";
9142
9119
  }
9143
9120
  for (const q of questions) {
9144
9121
  const data = answers[q.id];
9145
9122
  if (data && (data.options?.length ?? 0) === 0 && data.customText === "") {
9146
- return t ? t("error.customTextRequired", { question: q.text }) : `Please enter custom text for question: ${q.text}`;
9123
+ return t ? t("Error.CustomTextRequired", { question: q.text }) : `Please enter custom text for question: ${q.text}`;
9147
9124
  }
9148
9125
  }
9149
9126
  return null;
@@ -9196,7 +9173,7 @@ function QuestionForm({
9196
9173
  try {
9197
9174
  await onSubmit(answers);
9198
9175
  } catch (err) {
9199
- const errorMessage = err instanceof Error ? err.message : t("error.generic");
9176
+ const errorMessage = err instanceof Error ? err.message : t("Error.Generic");
9200
9177
  setError(errorMessage);
9201
9178
  setIsSubmitting(false);
9202
9179
  }
@@ -9213,7 +9190,7 @@ function QuestionForm({
9213
9190
  onClick: onCancel,
9214
9191
  disabled: isSubmitting,
9215
9192
  className: "cursor-pointer text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 disabled:opacity-50",
9216
- "aria-label": t("common.close"),
9193
+ "aria-label": t("Common.Close"),
9217
9194
  children: /* @__PURE__ */ jsxRuntime.jsx(react.X, { className: "w-6 h-6" })
9218
9195
  }
9219
9196
  )
@@ -9258,7 +9235,7 @@ function QuestionForm({
9258
9235
  onClick: onCancel,
9259
9236
  disabled: isSubmitting,
9260
9237
  className: "cursor-pointer px-6 py-2 text-gray-700 dark:text-gray-300 border border-gray-300 dark:border-gray-600 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 disabled:opacity-50 font-medium transition-colors",
9261
- children: t("message.cancel")
9238
+ children: t("Message.Cancel")
9262
9239
  }
9263
9240
  ),
9264
9241
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -9606,10 +9583,12 @@ function useStreaming(options = {}) {
9606
9583
  setError(null);
9607
9584
  setContent("");
9608
9585
  abortControllerRef.current = new AbortController();
9586
+ let onExternalAbort;
9609
9587
  if (signal) {
9610
- signal.addEventListener("abort", () => {
9588
+ onExternalAbort = () => {
9611
9589
  abortControllerRef.current?.abort();
9612
- });
9590
+ };
9591
+ signal.addEventListener("abort", onExternalAbort);
9613
9592
  }
9614
9593
  try {
9615
9594
  for await (const chunk of stream) {
@@ -9641,6 +9620,9 @@ function useStreaming(options = {}) {
9641
9620
  setError(errorObj);
9642
9621
  options.onError?.(errorObj.message);
9643
9622
  } finally {
9623
+ if (signal && onExternalAbort) {
9624
+ signal.removeEventListener("abort", onExternalAbort);
9625
+ }
9644
9626
  setIsStreaming(false);
9645
9627
  abortControllerRef.current = null;
9646
9628
  }
@@ -9981,9 +9963,6 @@ function useMessageActions(options = {}) {
9981
9963
  var DEFAULT_MAX_FILES = 10;
9982
9964
  var DEFAULT_MAX_FILE_SIZE = 20 * 1024 * 1024;
9983
9965
  var DEFAULT_ALLOWED_TYPES = [];
9984
- function generateId2() {
9985
- return `attachment-${Date.now()}-${Math.random().toString(36).substring(7)}`;
9986
- }
9987
9966
  function useAttachments(options = {}) {
9988
9967
  const {
9989
9968
  maxFiles = DEFAULT_MAX_FILES,
@@ -10079,7 +10058,7 @@ function useAttachments(options = {}) {
10079
10058
  continue;
10080
10059
  }
10081
10060
  const attachment = {
10082
- id: generateId2(),
10061
+ clientKey: crypto.randomUUID(),
10083
10062
  filename: file.name,
10084
10063
  mimeType: file.type,
10085
10064
  sizeBytes: file.size
@@ -10348,12 +10327,6 @@ function useRequiredConfig() {
10348
10327
  }
10349
10328
  return config;
10350
10329
  }
10351
- function hasPermission2(config, permission) {
10352
- if (!config) {
10353
- return false;
10354
- }
10355
- return config.user.permissions.includes(permission);
10356
- }
10357
10330
 
10358
10331
  // ui/src/bichat/theme/themes.ts
10359
10332
  var lightTheme = {
@@ -10605,6 +10578,62 @@ function elapsedMs(startedAt) {
10605
10578
 
10606
10579
  // ui/src/bichat/data/HttpDataSource.ts
10607
10580
  init_chartSpec();
10581
+
10582
+ // ui/src/bichat/utils/sseParser.ts
10583
+ function* processDataLines(lines) {
10584
+ for (const line of lines) {
10585
+ if (line.startsWith(":")) continue;
10586
+ if (line.startsWith("data: ")) {
10587
+ const jsonStr = line.slice(6);
10588
+ if (jsonStr === "[DONE]") continue;
10589
+ try {
10590
+ const parsed = JSON.parse(jsonStr);
10591
+ yield parsed;
10592
+ } catch (err) {
10593
+ console.error("SSE parse error:", err, "Data:", jsonStr);
10594
+ yield {
10595
+ type: "error",
10596
+ error: "Failed to parse SSE event"
10597
+ };
10598
+ }
10599
+ }
10600
+ }
10601
+ }
10602
+ async function* parseSSEStream(reader) {
10603
+ const decoder = new TextDecoder();
10604
+ let buffer = "";
10605
+ try {
10606
+ while (true) {
10607
+ const { done, value } = await reader.read();
10608
+ if (done) break;
10609
+ buffer += decoder.decode(value, { stream: true });
10610
+ const events = buffer.split("\n\n");
10611
+ buffer = events.pop() || "";
10612
+ for (const event of events) {
10613
+ if (!event.trim()) continue;
10614
+ yield* processDataLines(event.split("\n"));
10615
+ }
10616
+ }
10617
+ if (buffer.trim()) {
10618
+ yield* processDataLines(buffer.split("\n"));
10619
+ }
10620
+ } finally {
10621
+ reader.releaseLock();
10622
+ }
10623
+ }
10624
+ async function* parseBichatStream(reader) {
10625
+ for await (const event of parseSSEStream(reader)) {
10626
+ const parsed = event;
10627
+ const inferredType = parsed.type || (parsed.content ? "content" : "error");
10628
+ const normalized = {
10629
+ ...parsed,
10630
+ type: inferredType
10631
+ };
10632
+ yield normalized;
10633
+ }
10634
+ }
10635
+
10636
+ // ui/src/bichat/data/HttpDataSource.ts
10608
10637
  function toSession(session) {
10609
10638
  return {
10610
10639
  ...session,
@@ -10702,6 +10731,24 @@ function toDownloadArtifact(artifact) {
10702
10731
  description: artifact.description
10703
10732
  };
10704
10733
  }
10734
+ function normalizeAssistantTurn(turn) {
10735
+ return {
10736
+ ...turn,
10737
+ role: turn.role || "assistant" /* Assistant */,
10738
+ citations: turn.citations || [],
10739
+ artifacts: turn.artifacts || [],
10740
+ codeOutputs: turn.codeOutputs || []
10741
+ };
10742
+ }
10743
+ function normalizeTurns(raw) {
10744
+ return raw.map((turn) => {
10745
+ if (!turn.assistantTurn) return turn;
10746
+ return {
10747
+ ...turn,
10748
+ assistantTurn: normalizeAssistantTurn(turn.assistantTurn)
10749
+ };
10750
+ });
10751
+ }
10705
10752
  function toMillis(value) {
10706
10753
  const parsed = Date.parse(value);
10707
10754
  return Number.isFinite(parsed) ? parsed : Number.NaN;
@@ -10837,7 +10884,7 @@ var HttpDataSource = class {
10837
10884
  return { artifacts: [], hasMore: false, nextOffset: 0 };
10838
10885
  })
10839
10886
  ]);
10840
- const turns = attachArtifactsToTurns(data.turns, artifactsData.artifacts || []);
10887
+ const turns = attachArtifactsToTurns(normalizeTurns(data.turns), artifactsData.artifacts || []);
10841
10888
  return {
10842
10889
  session: toSession(data.session),
10843
10890
  turns,
@@ -10875,6 +10922,7 @@ var HttpDataSource = class {
10875
10922
  validateAttachmentFile(file);
10876
10923
  const base64Data = await convertToBase64(file);
10877
10924
  attachments.push({
10925
+ clientKey: crypto.randomUUID(),
10878
10926
  filename: file.name,
10879
10927
  mimeType: file.type,
10880
10928
  sizeBytes: file.size,
@@ -10885,6 +10933,7 @@ var HttpDataSource = class {
10885
10933
  sessionId,
10886
10934
  attachments: attachments.map((a) => ({
10887
10935
  id: "",
10936
+ // Backend will assign ID
10888
10937
  filename: a.filename,
10889
10938
  mimeType: a.mimeType,
10890
10939
  sizeBytes: a.sizeBytes,
@@ -10911,10 +10960,12 @@ var HttpDataSource = class {
10911
10960
  */
10912
10961
  async *sendMessage(sessionId, content, attachments = [], signal, options) {
10913
10962
  this.abortController = new AbortController();
10963
+ let onExternalAbort;
10914
10964
  if (signal) {
10915
- signal.addEventListener("abort", () => {
10965
+ onExternalAbort = () => {
10916
10966
  this.abortController?.abort();
10917
- });
10967
+ };
10968
+ signal.addEventListener("abort", onExternalAbort);
10918
10969
  }
10919
10970
  const url = `${this.config.baseUrl}${this.config.streamEndpoint}`;
10920
10971
  const payload = {
@@ -10944,48 +10995,11 @@ var HttpDataSource = class {
10944
10995
  throw new Error("Response body is null");
10945
10996
  }
10946
10997
  const reader = response.body.getReader();
10947
- const decoder = new TextDecoder();
10948
- let buffer = "";
10949
- try {
10950
- while (true) {
10951
- const { done, value } = await reader.read();
10952
- if (done) {
10953
- break;
10954
- }
10955
- buffer += decoder.decode(value, { stream: true });
10956
- const lines = buffer.split("\n");
10957
- buffer = lines.pop() || "";
10958
- for (const line of lines) {
10959
- if (!line.trim() || line.startsWith(":")) {
10960
- continue;
10961
- }
10962
- if (line.startsWith("data: ")) {
10963
- const data = line.slice(6);
10964
- try {
10965
- const parsed = JSON.parse(data);
10966
- const inferredType = parsed.type || (parsed.content || parsed.chunk ? "content" : "error");
10967
- const normalized = {
10968
- ...parsed,
10969
- type: inferredType,
10970
- content: parsed.content ?? parsed.chunk
10971
- };
10972
- yield normalized;
10973
- if (normalized.type === "done" || normalized.type === "error") {
10974
- return;
10975
- }
10976
- } catch (parseErr) {
10977
- console.error("Failed to parse SSE data:", parseErr);
10978
- yield {
10979
- type: "error",
10980
- error: "Failed to parse stream data"
10981
- };
10982
- return;
10983
- }
10984
- }
10985
- }
10998
+ for await (const chunk of parseBichatStream(reader)) {
10999
+ yield chunk;
11000
+ if (chunk.type === "done" || chunk.type === "error") {
11001
+ return;
10986
11002
  }
10987
- } finally {
10988
- reader.releaseLock();
10989
11003
  }
10990
11004
  } catch (err) {
10991
11005
  if (err instanceof Error) {
@@ -11007,6 +11021,9 @@ var HttpDataSource = class {
11007
11021
  };
11008
11022
  }
11009
11023
  } finally {
11024
+ if (signal && onExternalAbort) {
11025
+ signal.removeEventListener("abort", onExternalAbort);
11026
+ }
11010
11027
  this.abortController = null;
11011
11028
  }
11012
11029
  }
@@ -11118,72 +11135,6 @@ function createHttpDataSource(config) {
11118
11135
  return new HttpDataSource(config);
11119
11136
  }
11120
11137
 
11121
- // ui/src/bichat/index.ts
11122
- init_citationProcessor();
11123
-
11124
- // ui/src/bichat/utils/sseParser.ts
11125
- function* processDataLines(lines) {
11126
- for (const line of lines) {
11127
- if (line.startsWith(":")) continue;
11128
- if (line.startsWith("data: ")) {
11129
- const jsonStr = line.slice(6);
11130
- if (jsonStr === "[DONE]") continue;
11131
- try {
11132
- const parsed = JSON.parse(jsonStr);
11133
- yield parsed;
11134
- } catch (err) {
11135
- console.error("SSE parse error:", err, "Data:", jsonStr);
11136
- yield {
11137
- type: "error",
11138
- error: "Failed to parse SSE event"
11139
- };
11140
- }
11141
- }
11142
- }
11143
- }
11144
- async function* parseSSEStream(reader) {
11145
- const decoder = new TextDecoder();
11146
- let buffer = "";
11147
- try {
11148
- while (true) {
11149
- const { done, value } = await reader.read();
11150
- if (done) break;
11151
- buffer += decoder.decode(value, { stream: true });
11152
- const events = buffer.split("\n\n");
11153
- buffer = events.pop() || "";
11154
- for (const event of events) {
11155
- if (!event.trim()) continue;
11156
- yield* processDataLines(event.split("\n"));
11157
- }
11158
- }
11159
- if (buffer.trim()) {
11160
- yield* processDataLines(buffer.split("\n"));
11161
- }
11162
- } finally {
11163
- reader.releaseLock();
11164
- }
11165
- }
11166
- function formatRelativeTime(date, t) {
11167
- const messageDate = new Date(date);
11168
- const now = /* @__PURE__ */ new Date();
11169
- const diffMins = dateFns.differenceInMinutes(now, messageDate);
11170
- const diffHours = dateFns.differenceInHours(now, messageDate);
11171
- const diffDays = dateFns.differenceInDays(now, messageDate);
11172
- if (diffMins < 1) {
11173
- return t ? t("relativeTime.justNow") : "Just now";
11174
- }
11175
- if (diffMins < 60) {
11176
- return t ? t("relativeTime.minutesAgo", { count: diffMins }) : `${diffMins}m ago`;
11177
- }
11178
- if (diffHours < 24) {
11179
- return t ? t("relativeTime.hoursAgo", { count: diffHours }) : `${diffHours}h ago`;
11180
- }
11181
- if (diffDays <= 7) {
11182
- return t ? t("relativeTime.daysAgo", { count: diffDays }) : `${diffDays}d ago`;
11183
- }
11184
- return dateFns.format(messageDate, "HH:mm");
11185
- }
11186
-
11187
11138
  exports.ATTACHMENT_ACCEPT_ATTRIBUTE = ATTACHMENT_ACCEPT_ATTRIBUTE;
11188
11139
  exports.ActionButton = ActionButton;
11189
11140
  exports.Alert = Alert_default;
@@ -11276,22 +11227,16 @@ exports.fadeInUpVariants = fadeInUpVariants;
11276
11227
  exports.fadeInVariants = fadeInVariants;
11277
11228
  exports.floatingButtonVariants = floatingButtonVariants;
11278
11229
  exports.formatFileSize = formatFileSize;
11279
- exports.formatRelativeTime = formatRelativeTime;
11280
11230
  exports.getCSRFToken = getCSRFToken;
11281
11231
  exports.getFileVisual = getFileVisual;
11282
11232
  exports.getValidChildren = getValidChildren;
11283
11233
  exports.groupSessionsByDate = groupSessionsByDate;
11284
- exports.hasConfigPermission = hasPermission2;
11285
11234
  exports.hasPermission = hasPermission;
11286
11235
  exports.isImageMimeType = isImageMimeType;
11287
- exports.isQuestionAnswered = isQuestionAnswered;
11288
11236
  exports.lightTheme = lightTheme;
11289
11237
  exports.listItemVariants = listItemVariants;
11290
11238
  exports.messageContainerVariants = messageContainerVariants;
11291
11239
  exports.messageVariants = messageVariants;
11292
- exports.normalizeStreamingMarkdown = normalizeStreamingMarkdown;
11293
- exports.parseSSEStream = parseSSEStream;
11294
- exports.processCitations = processCitations;
11295
11240
  exports.scaleFadeVariants = scaleFadeVariants;
11296
11241
  exports.sessionItemVariants = sessionItemVariants;
11297
11242
  exports.staggerContainerVariants = staggerContainerVariants;
@@ -11302,7 +11247,6 @@ exports.useAttachments = useAttachments;
11302
11247
  exports.useAutoScroll = useAutoScroll;
11303
11248
  exports.useAvatarContext = useAvatarContext;
11304
11249
  exports.useBubbleContext = useBubbleContext;
11305
- exports.useChat = useChat;
11306
11250
  exports.useChatInput = useChatInput;
11307
11251
  exports.useChatMessaging = useChatMessaging;
11308
11252
  exports.useChatSession = useChatSession;
@@ -11323,7 +11267,6 @@ exports.useTheme = useTheme;
11323
11267
  exports.useToast = useToast;
11324
11268
  exports.useTranslation = useTranslation;
11325
11269
  exports.useTurnContext = useTurnContext;
11326
- exports.validateAnswers = validateAnswers;
11327
11270
  exports.validateAttachmentFile = validateAttachmentFile;
11328
11271
  exports.validateFileCount = validateFileCount;
11329
11272
  exports.validateImageFile = validateImageFile;