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.
- package/README.md +4 -2
- package/dist/client/assets/{CSPContext-DI-5GAnQ.js → CSPContext-TfUptlEu.js} +1 -1
- package/dist/client/assets/{DirectionContext-CrIsc5n9.js → DirectionContext-CQMv7g2N.js} +1 -1
- package/dist/client/assets/_sessionKey-DYknvaDS.js +23 -0
- package/dist/client/assets/agents-DNywJUai.js +2 -0
- package/dist/client/assets/agents-screen-fSZJpRi_.js +1 -0
- package/dist/client/assets/bots-Bqjqhws8.js +2 -0
- package/dist/client/assets/{bots-screen-BTKCOohV.js → bots-screen-4yT-e3cM.js} +1 -1
- package/dist/client/assets/{button-8ab4wOwy.js → button-DqP4GZwZ.js} +1 -1
- package/dist/client/assets/{composite-B2qsrzf3.js → composite-BLgu_EOL.js} +1 -1
- package/dist/client/assets/{connect-B3_p7C4I.js → connect-CiqRvR6s.js} +1 -1
- package/dist/client/assets/{dashboard-BtClHYpn.js → dashboard-CyWDWpbj.js} +1 -1
- package/dist/client/assets/event-2_Dxdv7h.js +1 -0
- package/dist/client/assets/file-explorer-screen-CZ2QKk-0.js +1 -0
- package/dist/client/assets/files-Cbhud0J8.js +2 -0
- package/dist/client/assets/follow-up-suggestions-Bi3Ci2my.js +5 -0
- package/dist/client/assets/{index-BXiha-Vz.js → index-C_gsW9fo.js} +1 -1
- package/dist/client/assets/{index-CtlYu8Ug.js → index-ygitKeM-.js} +1 -1
- package/dist/client/assets/keyboard-shortcuts-dialog-z-amTZVi.js +1 -0
- package/dist/client/assets/main-ZBMVSJTF.js +212 -0
- package/dist/client/assets/markdown-CHUjmWcv.js +87 -0
- package/dist/client/assets/memory-BRa-0plj.js +2 -0
- package/dist/client/assets/memory-screen-C_ZNDGLd.js +1 -0
- package/dist/client/assets/menu-CB88T7R1.js +1 -0
- package/dist/client/assets/{opencami-logo-BSed2Wez.js → opencami-logo-C0Kj1DiT.js} +1 -1
- package/dist/client/assets/proxy-D-juuhw6.js +9 -0
- package/dist/client/assets/{react-WkSlhZJd.js → react-Akh4y69S.js} +1 -1
- package/dist/client/assets/search-dialog-BasfzCyM.js +1 -0
- package/dist/client/assets/{search-sources-badge-Du8KpUEb.js → search-sources-badge-DwFHWd7S.js} +1 -1
- package/dist/client/assets/session-export-dialog-CAl3iJnD.js +1 -0
- package/dist/client/assets/settings-dialog-C8OoRXwX.js +1 -0
- package/dist/client/assets/skills-Cx12984a.js +2 -0
- package/dist/client/assets/{skills-panel-CVh1I-7D.js → skills-panel-B7BRAofP.js} +1 -1
- package/dist/client/assets/styles-CXa-SiWC.css +1 -0
- package/dist/client/assets/switch-DYEbEgy5.js +1 -0
- package/dist/client/assets/tabs-eiBvL0H7.js +1 -0
- package/dist/client/assets/thinking-CariuioI.js +1 -0
- package/dist/client/assets/tooltip-CekkGEYG.js +1 -0
- package/dist/client/assets/use-file-explorer-state-Dfyh4GwR.js +12 -0
- package/dist/client/assets/{useBaseUiId-DiwX_3so.js → useBaseUiId-DLhdkHJl.js} +1 -1
- package/dist/client/assets/{useCompositeItem-UPIPwR9H.js → useCompositeItem-DTSTTR0Z.js} +1 -1
- package/dist/client/assets/{useControlled-CT2hRlcU.js → useControlled-CpliTEve.js} +1 -1
- package/dist/client/assets/{useMutation-rx8UH99I.js → useMutation-CpD2Pn0F.js} +1 -1
- package/dist/client/assets/useOnFirstRender-DsFYFJoB.js +1 -0
- package/dist/client/assets/{useQuery-Boaa6oF3.js → useQuery-DMTgpIql.js} +1 -1
- package/dist/server/assets/{_sessionKey-B6iYeyCS.js → _sessionKey-Bhksr7VP.js} +267 -156
- package/dist/server/assets/{_tanstack-start-manifest_v-C9chPgNH.js → _tanstack-start-manifest_v-D-5ReiD4.js} +1 -1
- package/dist/server/assets/{agents-CmQ4vvXm.js → agents-BuE0Yum3.js} +1 -1
- package/dist/server/assets/{agents-screen-bmrIyFbk.js → agents-screen-CEQhbEwf.js} +3 -3
- package/dist/server/assets/{bots-Byt6jv0a.js → bots-BDHeSvSQ.js} +1 -1
- package/dist/server/assets/{bots-screen-C2TGFv42.js → bots-screen-C0NRS526.js} +2 -2
- package/dist/server/assets/{button-CwY2OHFj.js → button-kI8fEIZQ.js} +1 -1
- package/dist/server/assets/{connect-BNabuqpW.js → connect-CTVBm0Vc.js} +2 -2
- package/dist/server/assets/{file-explorer-screen-DH4UFK03.js → file-explorer-screen-FU_NhZmS.js} +4 -4
- package/dist/server/assets/{files-DYdXlQDr.js → files-DLxqp-h5.js} +1 -1
- package/dist/server/assets/{follow-up-suggestions-mzRQIB0k.js → follow-up-suggestions-B3hol2KT.js} +8 -8
- package/dist/server/assets/{index-COElhwGA.js → index-4G_4vZNY.js} +1 -1
- package/dist/server/assets/{index-BEWnDAH6.js → index-B_F4DTUu.js} +1 -1
- package/dist/server/assets/{keyboard-shortcuts-dialog-Cr6fOqHz.js → keyboard-shortcuts-dialog-Cp3ECNNi.js} +2 -2
- package/dist/server/assets/{markdown-DoX5Q7qh.js → markdown-CFdYXCRQ.js} +3 -3
- package/dist/server/assets/{memory-Cxu7i8ej.js → memory-rBB015W-.js} +1 -1
- package/dist/server/assets/{memory-screen-B5l1NZRY.js → memory-screen-vqXczcVo.js} +4 -4
- package/dist/server/assets/{menu-D90CDTi2.js → menu-D8cKTpmN.js} +1 -1
- package/dist/server/assets/{router-BqLGFd4L.js → router-C9JRmWMm.js} +142 -103
- package/dist/server/assets/{search-dialog-CmI7naPN.js → search-dialog-CTJULPB8.js} +8 -8
- package/dist/server/assets/{search-sources-badge-B0rAEDs_.js → search-sources-badge-B0t8Qffy.js} +1 -1
- package/dist/server/assets/{session-export-dialog-C53RRAah.js → session-export-dialog-CgtlOnwf.js} +2 -2
- package/dist/server/assets/{settings-dialog-BZ67gr9N.js → settings-dialog-B5yR2pBy.js} +35 -18
- package/dist/server/assets/{skills-Cy8xclXY.js → skills-BXUivxuo.js} +1 -1
- package/dist/server/assets/{skills-panel-BnRNb7u9.js → skills-panel-CDUp4jvw.js} +2 -2
- package/dist/server/assets/{switch-BbkUeVDV.js → switch-BZzwkgAQ.js} +1 -1
- package/dist/server/assets/{tabs-DDFZob0m.js → tabs-CWbp3mT4.js} +1 -1
- package/dist/server/assets/{thinking-CA8PSwKJ.js → thinking-CHx4Oouj.js} +8 -8
- package/dist/server/assets/{tooltip-DgsSPocE.js → tooltip-DOvOrSSS.js} +1 -1
- package/dist/server/assets/{use-file-explorer-state-s7CS50ho.js → use-file-explorer-state-E6cUvMva.js} +1 -1
- package/dist/server/server.js +195 -38
- package/package.json +1 -1
- package/dist/client/assets/_sessionKey-B4NZmxf3.js +0 -21
- package/dist/client/assets/agents-bptidK8z.js +0 -2
- package/dist/client/assets/agents-screen-6qdnPmx2.js +0 -1
- package/dist/client/assets/bots-BWpbaQ-E.js +0 -2
- package/dist/client/assets/event-DG3RKJz8.js +0 -1
- package/dist/client/assets/file-explorer-screen-Djl8x-8P.js +0 -1
- package/dist/client/assets/files-CjbCJDgC.js +0 -2
- package/dist/client/assets/follow-up-suggestions-BSCMXRXh.js +0 -5
- package/dist/client/assets/keyboard-shortcuts-dialog-HAufCn9C.js +0 -1
- package/dist/client/assets/main-CQKtcNr3.js +0 -210
- package/dist/client/assets/markdown-DFJF-FsV.js +0 -87
- package/dist/client/assets/memory-DnJOmcwU.js +0 -2
- package/dist/client/assets/memory-screen-Bm4NMAnU.js +0 -1
- package/dist/client/assets/menu-D26Vmgxl.js +0 -1
- package/dist/client/assets/popupStateMapping-DkI2OCkW.js +0 -1
- package/dist/client/assets/proxy-CHQ-VCN1.js +0 -9
- package/dist/client/assets/search-dialog-CCl4d0Pi.js +0 -1
- package/dist/client/assets/session-export-dialog-io9FvLKq.js +0 -1
- package/dist/client/assets/settings-dialog-B93qswor.js +0 -1
- package/dist/client/assets/skills-BNDGnHwM.js +0 -2
- package/dist/client/assets/styles-Ce2xZzc4.css +0 -1
- package/dist/client/assets/switch-CSnzINDW.js +0 -1
- package/dist/client/assets/tabs-CWfn44FL.js +0 -1
- package/dist/client/assets/thinking-BmoLlbFC.js +0 -1
- package/dist/client/assets/tooltip-CSGMH2t4.js +0 -1
- 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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
18
|
-
import { u as useChatSettings$1 } from "./index-
|
|
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-
|
|
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
|
|
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
|
-
|
|
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(),
|
|
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-
|
|
1689
|
+
() => import("./settings-dialog-B5yR2pBy.js").then((m) => ({ default: m.SettingsDialog }))
|
|
1685
1690
|
);
|
|
1686
1691
|
const SessionExportDialog = lazy(
|
|
1687
|
-
() => import("./session-export-dialog-
|
|
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-
|
|
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-
|
|
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
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
3890
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs text-
|
|
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-
|
|
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
|
-
|
|
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
|
-
|
|
5971
|
-
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
5975
|
-
|
|
5976
|
-
|
|
5977
|
-
|
|
5978
|
-
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
5982
|
-
|
|
5983
|
-
|
|
5984
|
-
|
|
5985
|
-
|
|
5986
|
-
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
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
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
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
|
-
|
|
5987
|
+
return;
|
|
6011
5988
|
}
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
const
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
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
|
-
|
|
6026
|
-
|
|
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
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
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-
|
|
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-
|
|
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:
|
|
6409
|
+
retry: 2,
|
|
6410
|
+
retryDelay: (attempt) => Math.min(2e3 * 2 ** attempt, 8e3),
|
|
6337
6411
|
refetchOnWindowFocus: false,
|
|
6338
|
-
refetchOnReconnect:
|
|
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,
|
|
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 (
|
|
6511
|
+
if (streaming.contentBlocks.length === 0) return null;
|
|
6434
6512
|
const content = [];
|
|
6435
|
-
for (const
|
|
6436
|
-
|
|
6437
|
-
type: "
|
|
6438
|
-
|
|
6439
|
-
|
|
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.
|
|
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.
|
|
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)
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
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
|
-
|
|
6465
|
-
|
|
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;
|