opencami 1.8.9 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/README.md +4 -2
  2. package/dist/client/assets/{CSPContext-DI-5GAnQ.js → CSPContext-TfUptlEu.js} +1 -1
  3. package/dist/client/assets/{DirectionContext-CrIsc5n9.js → DirectionContext-CQMv7g2N.js} +1 -1
  4. package/dist/client/assets/_sessionKey-DYknvaDS.js +23 -0
  5. package/dist/client/assets/agents-DNywJUai.js +2 -0
  6. package/dist/client/assets/agents-screen-fSZJpRi_.js +1 -0
  7. package/dist/client/assets/bots-Bqjqhws8.js +2 -0
  8. package/dist/client/assets/{bots-screen-BTKCOohV.js → bots-screen-4yT-e3cM.js} +1 -1
  9. package/dist/client/assets/{button-8ab4wOwy.js → button-DqP4GZwZ.js} +1 -1
  10. package/dist/client/assets/{composite-B2qsrzf3.js → composite-BLgu_EOL.js} +1 -1
  11. package/dist/client/assets/{connect-B3_p7C4I.js → connect-CiqRvR6s.js} +1 -1
  12. package/dist/client/assets/{dashboard-BtClHYpn.js → dashboard-CyWDWpbj.js} +1 -1
  13. package/dist/client/assets/event-2_Dxdv7h.js +1 -0
  14. package/dist/client/assets/file-explorer-screen-CZ2QKk-0.js +1 -0
  15. package/dist/client/assets/files-Cbhud0J8.js +2 -0
  16. package/dist/client/assets/follow-up-suggestions-Bi3Ci2my.js +5 -0
  17. package/dist/client/assets/{index-BXiha-Vz.js → index-C_gsW9fo.js} +1 -1
  18. package/dist/client/assets/{index-CtlYu8Ug.js → index-ygitKeM-.js} +1 -1
  19. package/dist/client/assets/keyboard-shortcuts-dialog-z-amTZVi.js +1 -0
  20. package/dist/client/assets/main-ZBMVSJTF.js +212 -0
  21. package/dist/client/assets/markdown-CHUjmWcv.js +87 -0
  22. package/dist/client/assets/memory-BRa-0plj.js +2 -0
  23. package/dist/client/assets/memory-screen-C_ZNDGLd.js +1 -0
  24. package/dist/client/assets/menu-CB88T7R1.js +1 -0
  25. package/dist/client/assets/{opencami-logo-BSed2Wez.js → opencami-logo-C0Kj1DiT.js} +1 -1
  26. package/dist/client/assets/proxy-D-juuhw6.js +9 -0
  27. package/dist/client/assets/{react-WkSlhZJd.js → react-Akh4y69S.js} +1 -1
  28. package/dist/client/assets/search-dialog-BasfzCyM.js +1 -0
  29. package/dist/client/assets/{search-sources-badge-Du8KpUEb.js → search-sources-badge-DwFHWd7S.js} +1 -1
  30. package/dist/client/assets/session-export-dialog-CAl3iJnD.js +1 -0
  31. package/dist/client/assets/settings-dialog-C8OoRXwX.js +1 -0
  32. package/dist/client/assets/skills-Cx12984a.js +2 -0
  33. package/dist/client/assets/{skills-panel-CVh1I-7D.js → skills-panel-B7BRAofP.js} +1 -1
  34. package/dist/client/assets/styles-CXa-SiWC.css +1 -0
  35. package/dist/client/assets/switch-DYEbEgy5.js +1 -0
  36. package/dist/client/assets/tabs-eiBvL0H7.js +1 -0
  37. package/dist/client/assets/thinking-CariuioI.js +1 -0
  38. package/dist/client/assets/tooltip-CekkGEYG.js +1 -0
  39. package/dist/client/assets/use-file-explorer-state-Dfyh4GwR.js +12 -0
  40. package/dist/client/assets/{useBaseUiId-DiwX_3so.js → useBaseUiId-DLhdkHJl.js} +1 -1
  41. package/dist/client/assets/{useCompositeItem-UPIPwR9H.js → useCompositeItem-DTSTTR0Z.js} +1 -1
  42. package/dist/client/assets/{useControlled-CT2hRlcU.js → useControlled-CpliTEve.js} +1 -1
  43. package/dist/client/assets/{useMutation-rx8UH99I.js → useMutation-CpD2Pn0F.js} +1 -1
  44. package/dist/client/assets/useOnFirstRender-DsFYFJoB.js +1 -0
  45. package/dist/client/assets/{useQuery-Boaa6oF3.js → useQuery-DMTgpIql.js} +1 -1
  46. package/dist/server/assets/{_sessionKey-B6iYeyCS.js → _sessionKey-Bhksr7VP.js} +267 -156
  47. package/dist/server/assets/{_tanstack-start-manifest_v-C9chPgNH.js → _tanstack-start-manifest_v-D-5ReiD4.js} +1 -1
  48. package/dist/server/assets/{agents-CmQ4vvXm.js → agents-BuE0Yum3.js} +1 -1
  49. package/dist/server/assets/{agents-screen-bmrIyFbk.js → agents-screen-CEQhbEwf.js} +3 -3
  50. package/dist/server/assets/{bots-Byt6jv0a.js → bots-BDHeSvSQ.js} +1 -1
  51. package/dist/server/assets/{bots-screen-C2TGFv42.js → bots-screen-C0NRS526.js} +2 -2
  52. package/dist/server/assets/{button-CwY2OHFj.js → button-kI8fEIZQ.js} +1 -1
  53. package/dist/server/assets/{connect-BNabuqpW.js → connect-CTVBm0Vc.js} +2 -2
  54. package/dist/server/assets/{file-explorer-screen-DH4UFK03.js → file-explorer-screen-FU_NhZmS.js} +4 -4
  55. package/dist/server/assets/{files-DYdXlQDr.js → files-DLxqp-h5.js} +1 -1
  56. package/dist/server/assets/{follow-up-suggestions-mzRQIB0k.js → follow-up-suggestions-B3hol2KT.js} +8 -8
  57. package/dist/server/assets/{index-COElhwGA.js → index-4G_4vZNY.js} +1 -1
  58. package/dist/server/assets/{index-BEWnDAH6.js → index-B_F4DTUu.js} +1 -1
  59. package/dist/server/assets/{keyboard-shortcuts-dialog-Cr6fOqHz.js → keyboard-shortcuts-dialog-Cp3ECNNi.js} +2 -2
  60. package/dist/server/assets/{markdown-DoX5Q7qh.js → markdown-CFdYXCRQ.js} +3 -3
  61. package/dist/server/assets/{memory-Cxu7i8ej.js → memory-rBB015W-.js} +1 -1
  62. package/dist/server/assets/{memory-screen-B5l1NZRY.js → memory-screen-vqXczcVo.js} +4 -4
  63. package/dist/server/assets/{menu-D90CDTi2.js → menu-D8cKTpmN.js} +1 -1
  64. package/dist/server/assets/{router-BqLGFd4L.js → router-C9JRmWMm.js} +142 -103
  65. package/dist/server/assets/{search-dialog-CmI7naPN.js → search-dialog-CTJULPB8.js} +8 -8
  66. package/dist/server/assets/{search-sources-badge-B0rAEDs_.js → search-sources-badge-B0t8Qffy.js} +1 -1
  67. package/dist/server/assets/{session-export-dialog-C53RRAah.js → session-export-dialog-CgtlOnwf.js} +2 -2
  68. package/dist/server/assets/{settings-dialog-BZ67gr9N.js → settings-dialog-B5yR2pBy.js} +35 -18
  69. package/dist/server/assets/{skills-Cy8xclXY.js → skills-BXUivxuo.js} +1 -1
  70. package/dist/server/assets/{skills-panel-BnRNb7u9.js → skills-panel-CDUp4jvw.js} +2 -2
  71. package/dist/server/assets/{switch-BbkUeVDV.js → switch-BZzwkgAQ.js} +1 -1
  72. package/dist/server/assets/{tabs-DDFZob0m.js → tabs-CWbp3mT4.js} +1 -1
  73. package/dist/server/assets/{thinking-CA8PSwKJ.js → thinking-CHx4Oouj.js} +8 -8
  74. package/dist/server/assets/{tooltip-DgsSPocE.js → tooltip-DOvOrSSS.js} +1 -1
  75. package/dist/server/assets/{use-file-explorer-state-s7CS50ho.js → use-file-explorer-state-E6cUvMva.js} +1 -1
  76. package/dist/server/server.js +195 -38
  77. package/package.json +1 -1
  78. package/dist/client/assets/_sessionKey-B4NZmxf3.js +0 -21
  79. package/dist/client/assets/agents-bptidK8z.js +0 -2
  80. package/dist/client/assets/agents-screen-6qdnPmx2.js +0 -1
  81. package/dist/client/assets/bots-BWpbaQ-E.js +0 -2
  82. package/dist/client/assets/event-DG3RKJz8.js +0 -1
  83. package/dist/client/assets/file-explorer-screen-Djl8x-8P.js +0 -1
  84. package/dist/client/assets/files-CjbCJDgC.js +0 -2
  85. package/dist/client/assets/follow-up-suggestions-BSCMXRXh.js +0 -5
  86. package/dist/client/assets/keyboard-shortcuts-dialog-HAufCn9C.js +0 -1
  87. package/dist/client/assets/main-CQKtcNr3.js +0 -210
  88. package/dist/client/assets/markdown-DFJF-FsV.js +0 -87
  89. package/dist/client/assets/memory-DnJOmcwU.js +0 -2
  90. package/dist/client/assets/memory-screen-Bm4NMAnU.js +0 -1
  91. package/dist/client/assets/menu-D26Vmgxl.js +0 -1
  92. package/dist/client/assets/popupStateMapping-DkI2OCkW.js +0 -1
  93. package/dist/client/assets/proxy-CHQ-VCN1.js +0 -9
  94. package/dist/client/assets/search-dialog-CCl4d0Pi.js +0 -1
  95. package/dist/client/assets/session-export-dialog-io9FvLKq.js +0 -1
  96. package/dist/client/assets/settings-dialog-B93qswor.js +0 -1
  97. package/dist/client/assets/skills-BNDGnHwM.js +0 -2
  98. package/dist/client/assets/styles-Ce2xZzc4.css +0 -1
  99. package/dist/client/assets/switch-CSnzINDW.js +0 -1
  100. package/dist/client/assets/tabs-CWfn44FL.js +0 -1
  101. package/dist/client/assets/thinking-BmoLlbFC.js +0 -1
  102. package/dist/client/assets/tooltip-CSGMH2t4.js +0 -1
  103. package/dist/client/assets/use-file-explorer-state-BYVzjwPA.js +0 -12
@@ -3,23 +3,23 @@ import { Link, useNavigate } from "@tanstack/react-router";
3
3
  import * as React from "react";
4
4
  import React__default, { useState, useCallback, memo, useDeferredValue, useMemo, Suspense, lazy, useRef, useEffect, useLayoutEffect, createContext, useContext } from "react";
5
5
  import { useQueryClient, useMutation, useQuery } from "@tanstack/react-query";
6
- import { T as TooltipProvider, a as TooltipRoot, b as TooltipTrigger, c as TooltipContent, s as setChatUiState, d as chatUiQueryKey, g as getChatUiState } from "./tooltip-DgsSPocE.js";
6
+ import { T as TooltipProvider, a as TooltipRoot, b as TooltipTrigger, c as TooltipContent, s as setChatUiState, d as chatUiQueryKey, g as getChatUiState } from "./tooltip-DOvOrSSS.js";
7
7
  import { Tick01Icon, Cancel01Icon, MoreHorizontalIcon, Pen01Icon, Upload01Icon, Delete01Icon, BotIcon, Clock01Icon, Chat01Icon, ArrowRight01Icon, SidebarLeft01Icon, PencilEdit02Icon, Folder01Icon, AiBrain01Icon, PackageOpenIcon, SmartPhone01Icon, DashboardCircleIcon, Search01Icon, Settings01Icon, Menu01Icon, Tick02Icon, Copy01Icon, Loading02Icon, StopIcon, VolumeHighIcon, Loading03Icon, ArrowDown01Icon, File01Icon, CommandIcon, Attachment01Icon, Mic02Icon, ArrowUp02Icon } from "@hugeicons/core-free-icons";
8
8
  import { HugeiconsIcon } from "@hugeicons/react";
9
9
  import { motion, AnimatePresence } from "motion/react";
10
10
  import { AlertDialog } from "@base-ui/react/alert-dialog";
11
- import { c as cn, B as Button, b as buttonVariants } from "./button-CwY2OHFj.js";
12
- import { D as DialogRoot, a as DialogContent, b as DialogTitle, c as DialogDescription, d as DialogClose, u as useFileExplorerState } from "./use-file-explorer-state-s7CS50ho.js";
11
+ import { c as cn, B as Button, b as buttonVariants } from "./button-kI8fEIZQ.js";
12
+ import { D as DialogRoot, a as DialogContent, b as DialogTitle, c as DialogDescription, d as DialogClose, u as useFileExplorerState } from "./use-file-explorer-state-E6cUvMva.js";
13
13
  import { Collapsible as Collapsible$1 } from "@base-ui/react/collapsible";
14
14
  import { ScrollArea } from "@base-ui/react/scroll-area";
15
- import { M as MenuRoot, a as MenuTrigger, b as MenuContent, c as MenuItem } from "./menu-D90CDTi2.js";
15
+ import { M as MenuRoot, a as MenuTrigger, b as MenuContent, c as MenuItem } from "./menu-D8cKTpmN.js";
16
16
  import { O as OpenCamiLogo, a as OpenCamiText } from "./opencami-logo-C-43FL3R.js";
17
- import { M as Markdown } from "./markdown-DoX5Q7qh.js";
18
- import { u as useChatSettings$1 } from "./index-BEWnDAH6.js";
17
+ import { M as Markdown } from "./markdown-CFdYXCRQ.js";
18
+ import { u as useChatSettings$1 } from "./index-B_F4DTUu.js";
19
19
  import { createPortal } from "react-dom";
20
20
  import { create } from "zustand";
21
21
  import { persist } from "zustand/middleware";
22
- import { a as Route } from "./router-BqLGFd4L.js";
22
+ import { a as Route } from "./router-C9JRmWMm.js";
23
23
  function deriveFriendlyIdFromKey(key) {
24
24
  if (!key) return "main";
25
25
  const trimmed = key.trim();
@@ -31,9 +31,16 @@ function deriveFriendlyIdFromKey(key) {
31
31
  }
32
32
  const INBOUND_META_FENCED_REGEX = /^Conversation info \(untrusted metadata\):\s*```(?:json)?\s*[\s\S]*?```\s*/;
33
33
  const INBOUND_META_INLINE_REGEX = /^Conversation info \(untrusted metadata\):\s*\{[\s\S]*?\}\s*/;
34
- const INBOUND_META_TIMESTAMP_REGEX = /^\[(?:[A-Za-z]{3}\s+)?\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}\s+GMT[+-]?\d+\]\s*/;
34
+ const INBOUND_SENDER_FENCED_REGEX = /^Sender \(untrusted metadata\):\s*```(?:[a-zA-Z0-9_-]+)?\s*[\s\S]*?```\s*/gm;
35
+ const INBOUND_SENDER_INLINE_REGEX = /^Sender \(untrusted metadata\):\s*\{[^\n]*\}\s*$/gm;
36
+ const SUPERMEMORY_CONTEXT_REGEX = /<supermemory-context\b[^>]*>[\s\S]*?<\/supermemory-context>/gi;
37
+ const SUPERMEMORY_CONTAINERS_REGEX = /<supermemory-containers\b[^>]*>[\s\S]*?<\/supermemory-containers>/gi;
38
+ const WORKSPACE_CRITICAL_RULES_REGEX = /<workspace-critical-rules\b[^>]*>[\s\S]*?<\/workspace-critical-rules>/gi;
39
+ const INBOUND_META_TIMESTAMP_REGEX = /^\[(?:[A-Za-z]{3}\s+)?\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}\s+GMT[+-]?\d+\]\s*/gm;
40
+ const MULTI_BLANK_LINES_REGEX = /\n{3,}/g;
35
41
  function stripInboundMeta(text) {
36
42
  let s = text;
43
+ s = s.replace(SUPERMEMORY_CONTEXT_REGEX, "").replace(SUPERMEMORY_CONTAINERS_REGEX, "").replace(WORKSPACE_CRITICAL_RULES_REGEX, "").replace(INBOUND_SENDER_FENCED_REGEX, "");
37
44
  const hasFenced = INBOUND_META_FENCED_REGEX.test(s);
38
45
  const hasInline = !hasFenced && INBOUND_META_INLINE_REGEX.test(s);
39
46
  if (hasFenced) {
@@ -41,9 +48,7 @@ function stripInboundMeta(text) {
41
48
  } else if (hasInline) {
42
49
  s = s.replace(INBOUND_META_INLINE_REGEX, "");
43
50
  }
44
- if (hasFenced || hasInline) {
45
- s = s.replace(INBOUND_META_TIMESTAMP_REGEX, "");
46
- }
51
+ s = s.replace(SUPERMEMORY_CONTEXT_REGEX, "").replace(SUPERMEMORY_CONTAINERS_REGEX, "").replace(INBOUND_SENDER_FENCED_REGEX, "").replace(INBOUND_SENDER_INLINE_REGEX, "").replace(INBOUND_META_TIMESTAMP_REGEX, "").replace(MULTI_BLANK_LINES_REGEX, "\n\n");
47
52
  return s.trim();
48
53
  }
49
54
  function textFromMessage(msg) {
@@ -201,7 +206,7 @@ async function fetchHistory(payload) {
201
206
  }
202
207
  async function fetchGatewayStatus() {
203
208
  const controller = new AbortController();
204
- const timeout = window.setTimeout(() => controller.abort(), 2500);
209
+ const timeout = window.setTimeout(() => controller.abort(), 8e3);
205
210
  try {
206
211
  const res = await fetch("/api/ping", { signal: controller.signal });
207
212
  if (!res.ok) throw new Error(await readError(res));
@@ -1681,10 +1686,10 @@ function areSidebarSessionsEqual(prev, next) {
1681
1686
  return true;
1682
1687
  }
1683
1688
  const SettingsDialog = lazy(
1684
- () => import("./settings-dialog-BZ67gr9N.js").then((m) => ({ default: m.SettingsDialog }))
1689
+ () => import("./settings-dialog-B5yR2pBy.js").then((m) => ({ default: m.SettingsDialog }))
1685
1690
  );
1686
1691
  const SessionExportDialog = lazy(
1687
- () => import("./session-export-dialog-C53RRAah.js").then((m) => ({
1692
+ () => import("./session-export-dialog-CgtlOnwf.js").then((m) => ({
1688
1693
  default: m.SessionExportDialog
1689
1694
  }))
1690
1695
  );
@@ -2444,17 +2449,17 @@ function ContextMeterComponent({
2444
2449
  ),
2445
2450
  children: [
2446
2451
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 mb-1.5", children: [
2447
- /* @__PURE__ */ jsx("span", { className: "text-primary-500 dark:text-primary-400", children: "Context window" }),
2452
+ /* @__PURE__ */ jsx("span", { className: "text-primary-500 dark:text-primary-500", children: "Context window" }),
2448
2453
  /* @__PURE__ */ jsxs("span", { className: cn("font-semibold", colors.text), children: [
2449
2454
  percentage,
2450
2455
  "%"
2451
2456
  ] })
2452
2457
  ] }),
2453
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-primary-700 dark:text-primary-300", children: [
2458
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 text-primary-700 dark:text-primary-700", children: [
2454
2459
  /* @__PURE__ */ jsx("span", { className: "font-medium", children: usedStr }),
2455
- /* @__PURE__ */ jsx("span", { className: "text-primary-400", children: "/" }),
2460
+ /* @__PURE__ */ jsx("span", { className: "text-primary-400 dark:text-primary-500", children: "/" }),
2456
2461
  /* @__PURE__ */ jsx("span", { children: maxStr }),
2457
- /* @__PURE__ */ jsx("span", { className: "text-primary-400", children: "tokens" })
2462
+ /* @__PURE__ */ jsx("span", { className: "text-primary-400 dark:text-primary-500", children: "tokens" })
2458
2463
  ] }),
2459
2464
  /* @__PURE__ */ jsx("div", { className: "w-full h-1.5 rounded-full bg-primary-200 dark:bg-primary-700 overflow-hidden mt-1.5", children: /* @__PURE__ */ jsx(
2460
2465
  "div",
@@ -2490,7 +2495,7 @@ function ChatHeaderComponent({
2490
2495
  {
2491
2496
  ref: wrapperRef,
2492
2497
  "data-tauri-drag-region": true,
2493
- className: "border-b border-primary-200 px-4 h-12 flex min-w-0 items-center overflow-x-hidden bg-surface tauri-drag-header",
2498
+ className: "border-b border-primary-200 pr-4 h-12 flex shrink-0 min-w-0 items-center bg-surface tauri-drag-header",
2494
2499
  children: [
2495
2500
  showSidebarButton ? /* @__PURE__ */ jsx(
2496
2501
  Button,
@@ -2828,12 +2833,12 @@ function Tool({ toolPart, defaultOpen = false }) {
2828
2833
  ] }) });
2829
2834
  }
2830
2835
  const Thinking = lazy(
2831
- () => import("./thinking-CA8PSwKJ.js").then((m) => ({
2836
+ () => import("./thinking-CHx4Oouj.js").then((m) => ({
2832
2837
  default: m.Thinking
2833
2838
  }))
2834
2839
  );
2835
2840
  const SearchSourcesBadge = lazy(
2836
- () => import("./search-sources-badge-B0rAEDs_.js").then((m) => ({
2841
+ () => import("./search-sources-badge-B0t8Qffy.js").then((m) => ({
2837
2842
  default: m.SearchSourcesBadge
2838
2843
  }))
2839
2844
  );
@@ -3469,7 +3474,7 @@ function TypingIndicator({ className }) {
3469
3474
  ] });
3470
3475
  }
3471
3476
  const FollowUpSuggestions = lazy(
3472
- () => import("./follow-up-suggestions-mzRQIB0k.js").then((m) => ({
3477
+ () => import("./follow-up-suggestions-B3hol2KT.js").then((m) => ({
3473
3478
  default: m.FollowUpSuggestions
3474
3479
  }))
3475
3480
  );
@@ -3886,8 +3891,8 @@ function SlashCommandMenuComponent({
3886
3891
  active ? "bg-neutral-800" : "hover:bg-neutral-800/80"
3887
3892
  ),
3888
3893
  children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
3889
- /* @__PURE__ */ jsx("code", { className: "min-w-[90px] font-mono text-xs text-primary-300", children: item.command }),
3890
- /* @__PURE__ */ jsx("span", { className: "text-xs text-neutral-300", children: item.description })
3894
+ /* @__PURE__ */ jsx("code", { className: "min-w-[90px] font-mono text-xs text-primary-700 dark:text-primary-700", children: item.command }),
3895
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-primary-600 dark:text-primary-600", children: item.description })
3891
3896
  ] })
3892
3897
  },
3893
3898
  item.command
@@ -3971,7 +3976,7 @@ function PromptInput({
3971
3976
  {
3972
3977
  onClick: handleClick,
3973
3978
  className: cn(
3974
- "bg-surface cursor-text rounded-[22px] outline outline-ink/10 shadow-[0px_12px_32px_0px_rgba(0,0,0,0.05)] py-3 gap-3 flex flex-col",
3979
+ "bg-surface dark:bg-primary-200 cursor-text rounded-[22px] outline outline-ink/10 shadow-[0px_12px_32px_0px_rgba(0,0,0,0.05)] py-3 gap-3 flex flex-col",
3975
3980
  disabled && "cursor-not-allowed opacity-60",
3976
3981
  className
3977
3982
  ),
@@ -4323,7 +4328,7 @@ function CommandHelp({ className, onCommandSelect }) {
4323
4328
  onClick: () => handleCommandClick(cmd.command),
4324
4329
  className: "w-full flex items-start gap-3 px-3 py-2 rounded-lg hover:bg-primary-100 dark:hover:bg-neutral-800 transition-colors text-left",
4325
4330
  children: [
4326
- /* @__PURE__ */ jsx("code", { className: "text-sm font-mono font-medium text-primary-700 dark:text-primary-300 bg-primary-100 dark:bg-neutral-800 px-1.5 py-0.5 rounded min-w-[80px]", children: cmd.command }),
4331
+ /* @__PURE__ */ jsx("code", { className: "text-sm font-mono font-medium text-primary-700 dark:text-primary-700 bg-primary-100 dark:bg-neutral-800 px-1.5 py-0.5 rounded min-w-[80px]", children: cmd.command }),
4327
4332
  /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
4328
4333
  /* @__PURE__ */ jsx("div", { className: "text-sm text-primary-900 dark:text-neutral-100", children: cmd.description }),
4329
4334
  cmd.usage && cmd.usage !== cmd.command && /* @__PURE__ */ jsx("div", { className: "text-xs text-primary-500 dark:text-neutral-500 font-mono mt-0.5", children: cmd.usage })
@@ -5901,61 +5906,32 @@ const INITIAL_STATE = {
5901
5906
  active: false,
5902
5907
  text: "",
5903
5908
  tools: [],
5909
+ contentBlocks: [],
5904
5910
  sessionKey: null
5905
5911
  };
5906
5912
  function useStreaming(options) {
5907
5913
  const [state, setState] = useState(INITIAL_STATE);
5908
5914
  const eventSourceRef = useRef(null);
5909
- const pollingRef = useRef(null);
5910
- const pollingTimeoutRef = useRef(null);
5911
- const streamStartRef = useRef(null);
5912
5915
  const doneRef = useRef(false);
5916
+ const finalStateRef = useRef(false);
5917
+ const activeRunsRef = useRef(/* @__PURE__ */ new Set());
5918
+ const lastSeqRef = useRef(-1);
5919
+ const lastAgentFingerprintRef = useRef("");
5920
+ const anyRunSeenRef = useRef(false);
5921
+ const sessionKeyRef = useRef("");
5913
5922
  const onDoneRef = useRef(options.onDone);
5914
5923
  const onErrorRef = useRef(options.onError);
5915
5924
  const onAssistantDeltaRef = useRef(options.onAssistantDelta);
5916
5925
  onDoneRef.current = options.onDone;
5917
5926
  onErrorRef.current = options.onError;
5918
5927
  onAssistantDeltaRef.current = options.onAssistantDelta;
5919
- function clearPolling() {
5920
- if (pollingTimeoutRef.current) {
5921
- window.clearTimeout(pollingTimeoutRef.current);
5922
- pollingTimeoutRef.current = null;
5923
- }
5924
- if (pollingRef.current) {
5925
- window.clearInterval(pollingRef.current);
5926
- pollingRef.current = null;
5927
- }
5928
- }
5929
- function startPolling(sessionKey, startedAt) {
5930
- if (pollingRef.current) return;
5931
- pollingRef.current = window.setInterval(async () => {
5932
- try {
5933
- const res = await fetch(
5934
- `/api/history?sessionKey=${encodeURIComponent(sessionKey)}`
5935
- );
5936
- if (!res.ok) return;
5937
- const data = await res.json();
5938
- const messages = Array.isArray(data.messages) ? data.messages : [];
5939
- const hasNewAssistant = messages.some((message) => {
5940
- if (!message || message.role !== "assistant") return false;
5941
- if (typeof message.timestamp !== "number") return false;
5942
- return message.timestamp > startedAt - 3e3;
5943
- });
5944
- if (!hasNewAssistant) return;
5945
- if (eventSourceRef.current) {
5946
- eventSourceRef.current.close();
5947
- eventSourceRef.current = null;
5948
- }
5949
- clearPolling();
5950
- setState((prev) => ({ ...prev, active: false }));
5951
- onDoneRef.current(sessionKey);
5952
- } catch {
5953
- }
5954
- }, 2e3);
5955
- }
5956
5928
  const stop = useCallback((options2) => {
5957
5929
  doneRef.current = true;
5958
- clearPolling();
5930
+ finalStateRef.current = false;
5931
+ activeRunsRef.current.clear();
5932
+ anyRunSeenRef.current = false;
5933
+ lastSeqRef.current = -1;
5934
+ lastAgentFingerprintRef.current = "";
5959
5935
  if (eventSourceRef.current) {
5960
5936
  eventSourceRef.current.close();
5961
5937
  eventSourceRef.current = null;
@@ -5966,80 +5942,177 @@ function useStreaming(options) {
5966
5942
  }
5967
5943
  setState(INITIAL_STATE);
5968
5944
  }, []);
5969
- const start = useCallback(
5970
- function start2(sessionKey) {
5971
- doneRef.current = false;
5972
- clearPolling();
5973
- streamStartRef.current = Date.now();
5974
- if (eventSourceRef.current) {
5975
- eventSourceRef.current.close();
5976
- eventSourceRef.current = null;
5977
- }
5978
- setState({
5979
- active: true,
5980
- text: "",
5981
- tools: [],
5982
- sessionKey
5983
- });
5984
- const es = new EventSource(`/api/stream?sessionKey=${encodeURIComponent(sessionKey)}`);
5985
- eventSourceRef.current = es;
5986
- es.addEventListener("delta", (e) => {
5987
- try {
5988
- const data = JSON.parse(e.data);
5989
- setState((prev) => ({
5990
- ...prev,
5991
- text: prev.text + data.text
5992
- }));
5993
- onAssistantDeltaRef.current?.({ text: data.text, sessionKey: data.sessionKey });
5994
- } catch {
5945
+ const start = useCallback(function start2(sessionKey) {
5946
+ sessionKeyRef.current = sessionKey;
5947
+ if (eventSourceRef.current && !doneRef.current) {
5948
+ setState((prev) => ({ ...prev, sessionKey, active: true }));
5949
+ return;
5950
+ }
5951
+ doneRef.current = false;
5952
+ finalStateRef.current = false;
5953
+ activeRunsRef.current.clear();
5954
+ anyRunSeenRef.current = false;
5955
+ lastSeqRef.current = -1;
5956
+ lastAgentFingerprintRef.current = "";
5957
+ setState({
5958
+ active: true,
5959
+ text: "",
5960
+ tools: [],
5961
+ contentBlocks: [],
5962
+ sessionKey
5963
+ });
5964
+ if (eventSourceRef.current) {
5965
+ return;
5966
+ }
5967
+ const es = new EventSource(`/api/stream?sessionKey=${encodeURIComponent(sessionKey)}`);
5968
+ eventSourceRef.current = es;
5969
+ es.addEventListener("message", (e) => {
5970
+ try {
5971
+ const data = JSON.parse(e.data);
5972
+ if (typeof data.seq === "number") {
5973
+ if (data.seq <= lastSeqRef.current) return;
5974
+ lastSeqRef.current = data.seq;
5995
5975
  }
5996
- });
5997
- es.addEventListener("tool", (e) => {
5998
- try {
5999
- const data = JSON.parse(e.data);
6000
- setState((prev) => {
6001
- const existingIdx = prev.tools.findIndex((t) => t.id === data.id);
6002
- const tools = [...prev.tools];
6003
- if (existingIdx >= 0) {
6004
- tools[existingIdx] = { name: data.name, status: data.status, id: data.id };
6005
- } else {
6006
- tools.push({ name: data.name, status: data.status, id: data.id });
6007
- }
6008
- return { ...prev, tools };
5976
+ const currentKey = sessionKeyRef.current;
5977
+ if (data.event === "agent") {
5978
+ const fp = JSON.stringify(data.payload);
5979
+ if (fp === lastAgentFingerprintRef.current) return;
5980
+ lastAgentFingerprintRef.current = fp;
5981
+ handleAgentEvent(data.payload, currentKey, {
5982
+ setState,
5983
+ onAssistantDelta: onAssistantDeltaRef.current,
5984
+ activeRuns: activeRunsRef.current,
5985
+ anyRunSeen: anyRunSeenRef
6009
5986
  });
6010
- } catch {
5987
+ return;
6011
5988
  }
6012
- });
6013
- es.addEventListener("done", (e) => {
6014
- try {
6015
- const data = JSON.parse(e.data);
6016
- doneRef.current = true;
6017
- clearPolling();
6018
- es.close();
6019
- eventSourceRef.current = null;
6020
- setState((prev) => ({ ...prev, active: false }));
6021
- onDoneRef.current(data.sessionKey);
6022
- } catch {
5989
+ if (data.event === "chat") {
5990
+ const chatPayload = asRecord(data.payload);
5991
+ const eventSessionKey = normalizeString(chatPayload?.sessionKey) || currentKey;
5992
+ const chatState = normalizeString(chatPayload?.state);
5993
+ if (chatState === "final") {
5994
+ finalStateRef.current = true;
5995
+ }
5996
+ if (!doneRef.current && finalStateRef.current && (chatState === "final" || anyRunSeenRef.current && activeRunsRef.current.size === 0)) {
5997
+ doneRef.current = true;
5998
+ setState((prev) => ({ ...prev, active: false }));
5999
+ onDoneRef.current(eventSessionKey);
6000
+ }
6001
+ return;
6023
6002
  }
6024
- });
6025
- es.onerror = () => {
6026
- if (es.readyState === EventSource.CLOSED) {
6027
- es.close();
6028
- eventSourceRef.current = null;
6029
- setState(INITIAL_STATE);
6030
- onErrorRef.current?.("Stream connection lost");
6003
+ if (data.event === "error") {
6004
+ const message = typeof data.payload === "string" ? data.payload : "Stream connection lost";
6005
+ onErrorRef.current?.(message);
6031
6006
  }
6032
- };
6033
- pollingTimeoutRef.current = window.setTimeout(() => {
6034
- if (doneRef.current) return;
6035
- const startedAt = streamStartRef.current ?? Date.now();
6036
- startPolling(sessionKey, startedAt);
6037
- }, 3e3);
6038
- },
6039
- []
6040
- );
6007
+ } catch {
6008
+ }
6009
+ });
6010
+ es.onerror = () => {
6011
+ if (doneRef.current) return;
6012
+ if (es.readyState === EventSource.CLOSED) {
6013
+ eventSourceRef.current = null;
6014
+ setState((prev) => ({ ...prev, active: false }));
6015
+ onErrorRef.current?.("Stream connection lost");
6016
+ }
6017
+ };
6018
+ }, []);
6041
6019
  return { streaming: state, startStream: start, stopStream: stop };
6042
6020
  }
6021
+ function handleAgentEvent(payload, fallbackSessionKey, options) {
6022
+ const agentPayload = asRecord(payload);
6023
+ const stream = normalizeString(agentPayload?.stream);
6024
+ const runId = normalizeString(agentPayload?.runId);
6025
+ const sessionKey = normalizeString(agentPayload?.sessionKey) || fallbackSessionKey;
6026
+ const streamData = asRecord(agentPayload?.data);
6027
+ if (runId) {
6028
+ options.anyRunSeen.current = true;
6029
+ if (stream === "lifecycle") {
6030
+ const phase = normalizeString(streamData?.phase);
6031
+ if (phase === "end" || phase === "error" || phase === "abort") {
6032
+ options.activeRuns.delete(runId);
6033
+ } else if (phase) {
6034
+ options.activeRuns.add(runId);
6035
+ }
6036
+ } else {
6037
+ options.activeRuns.add(runId);
6038
+ }
6039
+ }
6040
+ if (stream === "assistant") {
6041
+ const text = normalizeString(streamData?.delta) || normalizeString(streamData?.text);
6042
+ if (!text) return;
6043
+ options.setState((prev) => {
6044
+ const blocks = [...prev.contentBlocks];
6045
+ const lastBlock = blocks[blocks.length - 1];
6046
+ if (lastBlock?.kind === "text") {
6047
+ blocks[blocks.length - 1] = { ...lastBlock, text: lastBlock.text + text };
6048
+ } else {
6049
+ blocks.push({ kind: "text", text });
6050
+ }
6051
+ return {
6052
+ ...prev,
6053
+ sessionKey,
6054
+ text: prev.text + text,
6055
+ contentBlocks: blocks
6056
+ };
6057
+ });
6058
+ options.onAssistantDelta?.({ text, sessionKey });
6059
+ return;
6060
+ }
6061
+ if (!stream.includes("tool")) return;
6062
+ const toolId = normalizeString(streamData?.toolCallId) || normalizeString(streamData?.id) || normalizeString(streamData?.callId) || `${runId || "tool"}:${normalizeString(streamData?.toolName) || normalizeString(streamData?.name) || "unknown"}`;
6063
+ const toolName = normalizeString(streamData?.toolName) || normalizeString(streamData?.name) || "Tool";
6064
+ const toolStatus = deriveToolStatus(stream, streamData);
6065
+ const toolArgs = asRecord(streamData?.arguments) || asRecord(streamData?.input) || asRecord(streamData?.params) || null;
6066
+ const toolOutput = normalizeString(streamData?.result) || normalizeString(streamData?.output) || (stream.includes("result") ? normalizeString(streamData?.text) : "");
6067
+ options.setState((prev) => {
6068
+ const tools = [...prev.tools];
6069
+ const toolIndex = tools.findIndex((tool) => tool.id === toolId);
6070
+ const nextTool = { id: toolId, name: toolName, status: toolStatus };
6071
+ if (toolIndex >= 0) {
6072
+ tools[toolIndex] = nextTool;
6073
+ } else {
6074
+ tools.push(nextTool);
6075
+ }
6076
+ const blocks = [...prev.contentBlocks];
6077
+ const blockIndex = blocks.findIndex(
6078
+ (b) => b.kind === "tool" && b.id === toolId
6079
+ );
6080
+ const existingBlock = blockIndex >= 0 ? blocks[blockIndex] : null;
6081
+ const nextBlock = {
6082
+ kind: "tool",
6083
+ name: toolName,
6084
+ id: toolId,
6085
+ status: toolStatus,
6086
+ // Merge: keep existing arguments/output if new event doesn't carry them
6087
+ arguments: toolArgs ?? existingBlock?.arguments,
6088
+ output: toolOutput || existingBlock?.output || void 0
6089
+ };
6090
+ if (blockIndex >= 0) {
6091
+ blocks[blockIndex] = nextBlock;
6092
+ } else {
6093
+ blocks.push(nextBlock);
6094
+ }
6095
+ return {
6096
+ ...prev,
6097
+ sessionKey,
6098
+ tools,
6099
+ contentBlocks: blocks
6100
+ };
6101
+ });
6102
+ }
6103
+ function deriveToolStatus(stream, data) {
6104
+ const explicitStatus = normalizeString(data?.phase) || normalizeString(data?.status) || normalizeString(data?.state);
6105
+ if (explicitStatus) return explicitStatus;
6106
+ if (stream.includes("result") || stream.includes("output")) return "done";
6107
+ if (stream.includes("call")) return "running";
6108
+ return "running";
6109
+ }
6110
+ function asRecord(value) {
6111
+ return value && typeof value === "object" ? value : null;
6112
+ }
6113
+ function normalizeString(value) {
6114
+ return typeof value === "string" ? value.trim() : "";
6115
+ }
6043
6116
  function useKeyboardShortcuts(handlers) {
6044
6117
  const handleKeyDown = useCallback(
6045
6118
  (event) => {
@@ -6246,12 +6319,12 @@ function useNotifications() {
6246
6319
  };
6247
6320
  }
6248
6321
  const KeyboardShortcutsDialog = lazy(
6249
- () => import("./keyboard-shortcuts-dialog-Cr6fOqHz.js").then((m) => ({
6322
+ () => import("./keyboard-shortcuts-dialog-Cp3ECNNi.js").then((m) => ({
6250
6323
  default: m.KeyboardShortcutsDialog
6251
6324
  }))
6252
6325
  );
6253
6326
  const SearchDialog = lazy(
6254
- () => import("./search-dialog-CmI7naPN.js").then((m) => ({
6327
+ () => import("./search-dialog-CTJULPB8.js").then((m) => ({
6255
6328
  default: m.SearchDialog
6256
6329
  }))
6257
6330
  );
@@ -6333,9 +6406,10 @@ function ChatScreen({
6333
6406
  const gatewayStatusQuery = useQuery({
6334
6407
  queryKey: ["gateway", "status"],
6335
6408
  queryFn: fetchGatewayStatus,
6336
- retry: false,
6409
+ retry: 2,
6410
+ retryDelay: (attempt) => Math.min(2e3 * 2 ** attempt, 8e3),
6337
6411
  refetchOnWindowFocus: false,
6338
- refetchOnReconnect: false,
6412
+ refetchOnReconnect: true,
6339
6413
  refetchOnMount: "always"
6340
6414
  });
6341
6415
  const gatewayStatusMountRef = useRef(Date.now());
@@ -6345,6 +6419,11 @@ function ChatScreen({
6345
6419
  void gatewayStatusQuery.refetch();
6346
6420
  }, [gatewayStatusQuery]);
6347
6421
  const isSidebarCollapsed = uiQuery.data?.isSidebarCollapsed ?? false;
6422
+ useEffect(() => {
6423
+ if (sessionsQuery.isSuccess && gatewayStatusQuery.isError) {
6424
+ void gatewayStatusQuery.refetch();
6425
+ }
6426
+ }, [sessionsQuery.isSuccess, gatewayStatusQuery.isError]);
6348
6427
  const sidebarSwipeHandlers = useSwipeGesture({
6349
6428
  enabled: isMobile && isSidebarCollapsed,
6350
6429
  edgeWidth: 40,
@@ -6420,26 +6499,30 @@ function ChatScreen({
6420
6499
  handleStreamDoneRef.current = useCallback(
6421
6500
  async (_sk) => {
6422
6501
  await historyQuery.refetch();
6423
- stopStream({ preserveState: true });
6424
6502
  streamFinish();
6425
6503
  void queryClient.invalidateQueries({ queryKey: chatQueryKeys.sessions });
6426
6504
  },
6427
- [historyQuery, queryClient, stopStream, streamFinish]
6505
+ [historyQuery, queryClient, streamFinish]
6428
6506
  );
6429
6507
  handleStreamErrorRef.current = useCallback((_err) => {
6430
6508
  console.warn("[stream] SSE error, falling back to polling");
6431
6509
  }, []);
6432
6510
  const streamingMessage = useMemo(() => {
6433
- if (!streaming.text) return null;
6511
+ if (streaming.contentBlocks.length === 0) return null;
6434
6512
  const content = [];
6435
- for (const tool of streaming.tools) {
6436
- content.push({
6437
- type: "toolCall",
6438
- name: tool.name,
6439
- id: tool.id
6440
- });
6513
+ for (const block of streaming.contentBlocks) {
6514
+ if (block.kind === "text" && block.text) {
6515
+ content.push({ type: "text", text: block.text });
6516
+ } else if (block.kind === "tool") {
6517
+ content.push({
6518
+ type: "toolCall",
6519
+ name: block.name,
6520
+ id: block.id,
6521
+ arguments: block.arguments
6522
+ });
6523
+ }
6441
6524
  }
6442
- content.push({ type: "text", text: streaming.text });
6525
+ if (content.length === 0) return null;
6443
6526
  return {
6444
6527
  role: "assistant",
6445
6528
  content,
@@ -6447,22 +6530,46 @@ function ChatScreen({
6447
6530
  __streaming: true,
6448
6531
  timestamp: Date.now()
6449
6532
  };
6450
- }, [streaming.text, streaming.tools]);
6533
+ }, [streaming.contentBlocks]);
6534
+ const streamingToolResults = useMemo(() => {
6535
+ const results = [];
6536
+ for (const block of streaming.contentBlocks) {
6537
+ if (block.kind === "tool" && block.status === "done") {
6538
+ results.push({
6539
+ role: "toolResult",
6540
+ toolCallId: block.id,
6541
+ toolName: block.name,
6542
+ content: block.output ? [{ type: "text", text: block.output }] : []
6543
+ });
6544
+ }
6545
+ }
6546
+ return results;
6547
+ }, [streaming.contentBlocks]);
6451
6548
  const messagesWithStreaming = useMemo(() => {
6452
6549
  if (!streamingMessage) return displayMessages;
6453
6550
  const lastAssistantIndex = [...displayMessages].map((message, index) => ({ message, index })).filter(({ message }) => message.role === "assistant").map(({ index }) => index).pop();
6454
6551
  const lastUserIndex = [...displayMessages].map((message, index) => ({ message, index })).filter(({ message }) => message.role === "user").map(({ index }) => index).pop();
6455
6552
  const assistantIsLatestTurn = typeof lastAssistantIndex === "number" && (typeof lastUserIndex !== "number" || lastAssistantIndex > lastUserIndex);
6553
+ if (!streaming.active && assistantIsLatestTurn) {
6554
+ return displayMessages;
6555
+ }
6556
+ let merged;
6456
6557
  if (assistantIsLatestTurn && typeof lastAssistantIndex === "number") {
6457
6558
  const historyAssistant = displayMessages[lastAssistantIndex];
6458
6559
  const historyText = textFromMessage(historyAssistant);
6459
- if (historyText.length >= streaming.text.length) return displayMessages;
6460
- const msgs = [...displayMessages];
6461
- msgs[lastAssistantIndex] = streamingMessage;
6462
- return msgs;
6560
+ if (historyText.length >= streaming.text.length && streaming.tools.length === 0) {
6561
+ return displayMessages;
6562
+ }
6563
+ merged = [...displayMessages];
6564
+ merged[lastAssistantIndex] = streamingMessage;
6565
+ } else {
6566
+ merged = [...displayMessages, streamingMessage];
6463
6567
  }
6464
- return [...displayMessages, streamingMessage];
6465
- }, [displayMessages, streamingMessage, streaming.text]);
6568
+ if (streamingToolResults.length > 0) {
6569
+ merged = [...merged, ...streamingToolResults];
6570
+ }
6571
+ return merged;
6572
+ }, [displayMessages, streamingMessage, streamingToolResults, streaming.active, streaming.text, streaming.tools]);
6466
6573
  const stableContentStyle = useMemo(() => ({}), []);
6467
6574
  refreshHistoryRef.current = function refreshHistory() {
6468
6575
  void historyQuery.refetch();
@@ -6733,6 +6840,10 @@ function ChatScreen({
6733
6840
  }));
6734
6841
  streamingNotificationTextRef.current = "";
6735
6842
  streamStart();
6843
+ const preStreamKey = sessionKey || friendlyId;
6844
+ if (preStreamKey) {
6845
+ startStream(preStreamKey);
6846
+ }
6736
6847
  fetch("/api/send", {
6737
6848
  method: "POST",
6738
6849
  headers: { "content-type": "application/json" },
@@ -6956,7 +7067,7 @@ function ChatScreen({
6956
7067
  });
6957
7068
  const historyLoading = historyQuery.isLoading && !historyQuery.data || isRedirecting;
6958
7069
  const showGatewayDown = Boolean(gatewayStatusError);
6959
- const showGatewayNotice = showGatewayDown && gatewayStatusQuery.errorUpdatedAt > gatewayStatusMountRef.current;
7070
+ const showGatewayNotice = showGatewayDown && !sessionsQuery.isSuccess && gatewayStatusQuery.errorUpdatedAt > gatewayStatusMountRef.current;
6960
7071
  const historyEmpty = !historyLoading && displayMessages.length === 0;
6961
7072
  const gatewayNotice = useMemo(() => {
6962
7073
  if (!showGatewayNotice) return null;