@flamingo-stack/openframe-frontend-core 0.0.443 → 0.0.444-snapshot.20260717182533
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-DOVBNECK.js → chunk-22NSWMI6.js} +3 -3
- package/dist/{chunk-NQODKJ2F.js → chunk-3BHV2QAH.js} +561 -145
- package/dist/chunk-3BHV2QAH.js.map +1 -0
- package/dist/{chunk-3ZE55IH6.js → chunk-3DQ5BFPM.js} +5 -5
- package/dist/{chunk-KNNSS3CZ.cjs → chunk-3HYSD7NR.cjs} +15 -15
- package/dist/{chunk-KNNSS3CZ.cjs.map → chunk-3HYSD7NR.cjs.map} +1 -1
- package/dist/{chunk-ZVAAIP5Y.cjs → chunk-5DWPXK37.cjs} +40 -40
- package/dist/{chunk-ZVAAIP5Y.cjs.map → chunk-5DWPXK37.cjs.map} +1 -1
- package/dist/{chunk-323TCNF3.cjs → chunk-5FUQTSTT.cjs} +18 -18
- package/dist/{chunk-323TCNF3.cjs.map → chunk-5FUQTSTT.cjs.map} +1 -1
- package/dist/{chunk-MG4AMIFX.js → chunk-5NYXGWBN.js} +2 -2
- package/dist/{chunk-UXJ47OJF.js → chunk-7R256DKK.js} +2 -2
- package/dist/{chunk-OHKKI6EF.cjs → chunk-DTLNCOSG.cjs} +32 -32
- package/dist/{chunk-OHKKI6EF.cjs.map → chunk-DTLNCOSG.cjs.map} +1 -1
- package/dist/{chunk-LYYVTI34.js → chunk-FIAXFNAA.js} +5 -5
- package/dist/{chunk-FQASXKBK.js → chunk-G2KXNMFQ.js} +2 -2
- package/dist/{chunk-RQVR7I73.js → chunk-H2DYCT6M.js} +2 -2
- package/dist/{chunk-6IPNXMB7.js → chunk-H352AZJN.js} +6 -6
- package/dist/{chunk-A7MG4SBL.js → chunk-K4RASNQM.js} +3 -3
- package/dist/{chunk-PRJFSF4W.cjs → chunk-KISQUH33.cjs} +73 -73
- package/dist/{chunk-PRJFSF4W.cjs.map → chunk-KISQUH33.cjs.map} +1 -1
- package/dist/{chunk-M6XUXQ5Q.cjs → chunk-MPSA6YAM.cjs} +40 -40
- package/dist/{chunk-M6XUXQ5Q.cjs.map → chunk-MPSA6YAM.cjs.map} +1 -1
- package/dist/{chunk-PVMPBWKX.js → chunk-MQUS6BFR.js} +6 -6
- package/dist/{chunk-H4W3NCR2.cjs → chunk-N64VTHZ5.cjs} +7 -7
- package/dist/{chunk-H4W3NCR2.cjs.map → chunk-N64VTHZ5.cjs.map} +1 -1
- package/dist/{chunk-VACXEUGF.cjs → chunk-P3FN4NAE.cjs} +29 -29
- package/dist/{chunk-VACXEUGF.cjs.map → chunk-P3FN4NAE.cjs.map} +1 -1
- package/dist/{chunk-PHWQLKVE.js → chunk-P47NN7RY.js} +29 -31
- package/dist/chunk-P47NN7RY.js.map +1 -0
- package/dist/{chunk-2CJ734N2.cjs → chunk-PTT4J5GF.cjs} +3 -3
- package/dist/{chunk-2CJ734N2.cjs.map → chunk-PTT4J5GF.cjs.map} +1 -1
- package/dist/{chunk-IBIGXER5.cjs → chunk-QL2EI56X.cjs} +803 -387
- package/dist/chunk-QL2EI56X.cjs.map +1 -0
- package/dist/{chunk-YPFQ2UIH.cjs → chunk-R6WGCJBB.cjs} +73 -73
- package/dist/{chunk-YPFQ2UIH.cjs.map → chunk-R6WGCJBB.cjs.map} +1 -1
- package/dist/{chunk-6NO4YYU7.cjs → chunk-RXLMN6B5.cjs} +12 -12
- package/dist/{chunk-6NO4YYU7.cjs.map → chunk-RXLMN6B5.cjs.map} +1 -1
- package/dist/{chunk-AZQOX2RS.js → chunk-TCEBFMLQ.js} +2 -2
- package/dist/{chunk-7CZ4MJSI.cjs → chunk-VIJARDBM.cjs} +3 -3
- package/dist/{chunk-7CZ4MJSI.cjs.map → chunk-VIJARDBM.cjs.map} +1 -1
- package/dist/{chunk-PXXS27EE.cjs → chunk-W24U7ZUV.cjs} +40 -42
- package/dist/chunk-W24U7ZUV.cjs.map +1 -0
- package/dist/{chunk-5U6OZ5FD.js → chunk-XPZLIONZ.js} +4 -4
- package/dist/{chunk-RYKANQE6.cjs → chunk-YCLSV2H6.cjs} +5 -5
- package/dist/{chunk-RYKANQE6.cjs.map → chunk-YCLSV2H6.cjs.map} +1 -1
- package/dist/{chunk-LGMRNYTX.js → chunk-Z4N7XLFG.js} +3 -3
- package/dist/components/case-studies/index.cjs +10 -10
- package/dist/components/case-studies/index.js +4 -4
- package/dist/components/chat/hooks/use-chunk-catchup.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-jetstream-dialog-subscription.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts +44 -1
- package/dist/components/chat/hooks/use-nats-chat-adapter.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-nats-dialog-subscription.d.ts.map +1 -1
- package/dist/components/chat/hooks/use-realtime-chunk-processor.d.ts.map +1 -1
- package/dist/components/chat/index.cjs +10 -4
- package/dist/components/chat/index.cjs.map +1 -1
- package/dist/components/chat/index.js +9 -3
- package/dist/components/chat/utils/message-segment-accumulator.d.ts.map +1 -1
- package/dist/components/chat/utils/process-historical-messages.d.ts.map +1 -1
- package/dist/components/contact/index.cjs +5 -5
- package/dist/components/contact/index.js +4 -4
- package/dist/components/docs/index.cjs +7 -7
- package/dist/components/docs/index.js +6 -6
- package/dist/components/embeds/index.cjs +5 -5
- package/dist/components/embeds/index.js +4 -4
- package/dist/components/faq/index.cjs +6 -6
- package/dist/components/faq/index.js +5 -5
- package/dist/components/features/index.cjs +4 -4
- package/dist/components/features/index.js +3 -3
- package/dist/components/features/policy-configuration-panel.d.ts.map +1 -1
- package/dist/components/help-center-pages/index.cjs +23 -23
- package/dist/components/help-center-pages/index.js +14 -14
- package/dist/components/index.cjs +142 -136
- package/dist/components/index.cjs.map +1 -1
- package/dist/components/index.js +18 -12
- package/dist/components/index.js.map +1 -1
- package/dist/components/navigation/index.cjs +4 -4
- package/dist/components/navigation/index.js +3 -3
- package/dist/components/onboarding-guides/index.cjs +8 -8
- package/dist/components/onboarding-guides/index.js +7 -7
- package/dist/components/related-content/index.cjs +6 -6
- package/dist/components/related-content/index.js +5 -5
- package/dist/components/tickets/index.cjs +7 -7
- package/dist/components/tickets/index.js +6 -6
- package/dist/components/ui/checkbox-block.d.ts +6 -0
- package/dist/components/ui/checkbox-block.d.ts.map +1 -1
- package/dist/components/ui/index.cjs +10 -4
- package/dist/components/ui/index.cjs.map +1 -1
- package/dist/components/ui/index.js +9 -3
- package/dist/hooks/index.cjs +3 -3
- package/dist/hooks/index.js +2 -2
- package/dist/index.cjs +10 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +9 -3
- package/dist/nats/index.cjs +2 -2
- package/dist/nats/index.js +1 -1
- package/dist/nats/shared-connection.d.ts +6 -0
- package/dist/nats/shared-connection.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/chat/hooks/__tests__/nats-adapter-message-updaters.test.ts +270 -0
- package/src/components/chat/hooks/use-chunk-catchup.ts +212 -57
- package/src/components/chat/hooks/use-jetstream-dialog-subscription.ts +12 -8
- package/src/components/chat/hooks/use-nats-chat-adapter.ts +574 -9
- package/src/components/chat/hooks/use-nats-dialog-subscription.ts +12 -6
- package/src/components/chat/hooks/use-realtime-chunk-processor.ts +40 -3
- package/src/components/chat/utils/__tests__/process-historical-messages-approvals.test.ts +62 -0
- package/src/components/chat/utils/message-segment-accumulator.ts +6 -0
- package/src/components/chat/utils/process-historical-messages.ts +25 -3
- package/src/components/features/policy-configuration-panel.tsx +1 -4
- package/src/components/ui/checkbox-block.tsx +12 -1
- package/src/nats/shared-connection.ts +42 -29
- package/src/stories/CheckboxBlock.stories.tsx +18 -0
- package/dist/chunk-IBIGXER5.cjs.map +0 -1
- package/dist/chunk-NQODKJ2F.js.map +0 -1
- package/dist/chunk-PHWQLKVE.js.map +0 -1
- package/dist/chunk-PXXS27EE.cjs.map +0 -1
- /package/dist/{chunk-DOVBNECK.js.map → chunk-22NSWMI6.js.map} +0 -0
- /package/dist/{chunk-3ZE55IH6.js.map → chunk-3DQ5BFPM.js.map} +0 -0
- /package/dist/{chunk-MG4AMIFX.js.map → chunk-5NYXGWBN.js.map} +0 -0
- /package/dist/{chunk-UXJ47OJF.js.map → chunk-7R256DKK.js.map} +0 -0
- /package/dist/{chunk-LYYVTI34.js.map → chunk-FIAXFNAA.js.map} +0 -0
- /package/dist/{chunk-FQASXKBK.js.map → chunk-G2KXNMFQ.js.map} +0 -0
- /package/dist/{chunk-RQVR7I73.js.map → chunk-H2DYCT6M.js.map} +0 -0
- /package/dist/{chunk-6IPNXMB7.js.map → chunk-H352AZJN.js.map} +0 -0
- /package/dist/{chunk-A7MG4SBL.js.map → chunk-K4RASNQM.js.map} +0 -0
- /package/dist/{chunk-PVMPBWKX.js.map → chunk-MQUS6BFR.js.map} +0 -0
- /package/dist/{chunk-AZQOX2RS.js.map → chunk-TCEBFMLQ.js.map} +0 -0
- /package/dist/{chunk-5U6OZ5FD.js.map → chunk-XPZLIONZ.js.map} +0 -0
- /package/dist/{chunk-LGMRNYTX.js.map → chunk-Z4N7XLFG.js.map} +0 -0
|
@@ -27,7 +27,7 @@ import {
|
|
|
27
27
|
useOgPlaceholderUrl,
|
|
28
28
|
useOnboardingState,
|
|
29
29
|
useToast
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-5NYXGWBN.js";
|
|
31
31
|
import {
|
|
32
32
|
AlertCircleIcon,
|
|
33
33
|
AnthropicLogoGreyIcon,
|
|
@@ -249,7 +249,7 @@ import {
|
|
|
249
249
|
acquireClient,
|
|
250
250
|
releaseClient,
|
|
251
251
|
startConnectionLifecycle
|
|
252
|
-
} from "./chunk-
|
|
252
|
+
} from "./chunk-P47NN7RY.js";
|
|
253
253
|
import {
|
|
254
254
|
__esm
|
|
255
255
|
} from "./chunk-GGWZFCYS.js";
|
|
@@ -14000,13 +14000,15 @@ import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
|
|
14000
14000
|
import * as React40 from "react";
|
|
14001
14001
|
init_cn();
|
|
14002
14002
|
import { jsx as jsx96, jsxs as jsxs74 } from "react/jsx-runtime";
|
|
14003
|
-
var CheckboxBlock = React40.forwardRef(({ id, checked, defaultChecked, onCheckedChange, label, description, truncateLabel, disabled, error, className }, ref) => /* @__PURE__ */ jsxs74("div", { className: cn("relative flex w-full flex-col", className), children: [
|
|
14003
|
+
var CheckboxBlock = React40.forwardRef(({ id, checked, defaultChecked, onCheckedChange, label, description, truncateLabel, trailing, disabled, error, className }, ref) => /* @__PURE__ */ jsxs74("div", { className: cn("relative flex w-full flex-col", className), children: [
|
|
14004
14004
|
/* @__PURE__ */ jsxs74(
|
|
14005
14005
|
"label",
|
|
14006
14006
|
{
|
|
14007
14007
|
htmlFor: id,
|
|
14008
14008
|
className: cn(
|
|
14009
14009
|
"flex items-center gap-[var(--spacing-system-s)] rounded-md ring-1 ring-inset w-full",
|
|
14010
|
+
// Trailing content stacks full-width below the text on mobile.
|
|
14011
|
+
trailing && "flex-wrap md:flex-nowrap",
|
|
14010
14012
|
"p-[var(--spacing-system-sf)]",
|
|
14011
14013
|
!description && "min-h-[44px] md:min-h-[48px]",
|
|
14012
14014
|
description && "min-h-[60px] md:min-h-[64px]",
|
|
@@ -14054,7 +14056,8 @@ var CheckboxBlock = React40.forwardRef(({ id, checked, defaultChecked, onChecked
|
|
|
14054
14056
|
"text-h6 !leading-4",
|
|
14055
14057
|
"text-ods-text-secondary select-none break-words"
|
|
14056
14058
|
), children: description })
|
|
14057
|
-
] })
|
|
14059
|
+
] }),
|
|
14060
|
+
trailing && /* @__PURE__ */ jsx96("div", { className: "flex w-full shrink-0 items-center md:ml-auto md:w-auto", children: trailing })
|
|
14058
14061
|
]
|
|
14059
14062
|
}
|
|
14060
14063
|
),
|
|
@@ -31988,14 +31991,7 @@ var PolicyRow = ({ policy, categoryId, editMode, onPermissionChange }) => {
|
|
|
31988
31991
|
/* @__PURE__ */ jsx253("div", { className: "bg-ods-bg border border-ods-border rounded-md flex items-center justify-center w-8 h-8 shrink-0", children: /* @__PURE__ */ jsx253(ToolIcon, { toolType: policy.toolName, size: 16 }) }),
|
|
31989
31992
|
/* @__PURE__ */ jsxs197("div", { className: "flex-1 flex flex-col min-w-0", children: [
|
|
31990
31993
|
/* @__PURE__ */ jsx253("p", { className: "text-h4 text-ods-text-primary truncate", title: policy.name, children: policy.name }),
|
|
31991
|
-
/* @__PURE__ */ jsx253(
|
|
31992
|
-
"p",
|
|
31993
|
-
{
|
|
31994
|
-
className: "text-h6 text-ods-text-secondary truncate md:whitespace-normal md:break-all",
|
|
31995
|
-
title: policy.commandPattern,
|
|
31996
|
-
children: policy.commandPattern
|
|
31997
|
-
}
|
|
31998
|
-
),
|
|
31994
|
+
/* @__PURE__ */ jsx253("p", { className: "text-h6 text-ods-text-secondary break-all", children: policy.commandPattern }),
|
|
31999
31995
|
editMode ? /* @__PURE__ */ jsx253("div", { className: "md:hidden mt-[var(--spacing-system-xsf)]", children: /* @__PURE__ */ jsx253(
|
|
32000
31996
|
ApprovalLevelDropdown,
|
|
32001
31997
|
{
|
|
@@ -46960,8 +46956,10 @@ function useChunkCatchup({
|
|
|
46960
46956
|
}) {
|
|
46961
46957
|
const processedSequenceKeys = useRef64(/* @__PURE__ */ new Set());
|
|
46962
46958
|
const lastSequenceId = useRef64(null);
|
|
46959
|
+
const lastSequenceIdByType = useRef64(/* @__PURE__ */ new Map());
|
|
46963
46960
|
const fetchingInProgress = useRef64(false);
|
|
46964
46961
|
const lastFetchParams = useRef64(null);
|
|
46962
|
+
const pendingCatchupRef = useRef64(null);
|
|
46965
46963
|
const chunkBuffer = useRef64([]);
|
|
46966
46964
|
const bufferUntilInitialCatchupComplete = useRef64(false);
|
|
46967
46965
|
const hasCompletedInitialCatchup = useRef64(false);
|
|
@@ -46980,8 +46978,14 @@ function useChunkCatchup({
|
|
|
46980
46978
|
}
|
|
46981
46979
|
if (chunk.sequenceId !== void 0 && chunk.sequenceId !== null) {
|
|
46982
46980
|
const chunkType = typeof chunk.type === "string" ? chunk.type : "";
|
|
46983
|
-
|
|
46981
|
+
const key = makeSeqKey(messageType, chunkType, chunk.sequenceId);
|
|
46982
|
+
if (processedSequenceKeys.current.has(key)) return true;
|
|
46983
|
+
processedSequenceKeys.current.add(key);
|
|
46984
46984
|
lastSequenceId.current = chunk.sequenceId;
|
|
46985
|
+
const prevTypeSeq = lastSequenceIdByType.current.get(messageType);
|
|
46986
|
+
if (prevTypeSeq === void 0 || chunk.sequenceId > prevTypeSeq) {
|
|
46987
|
+
lastSequenceIdByType.current.set(messageType, chunk.sequenceId);
|
|
46988
|
+
}
|
|
46985
46989
|
}
|
|
46986
46990
|
onChunkReceivedRef.current(chunk, messageType);
|
|
46987
46991
|
return true;
|
|
@@ -46991,8 +46995,8 @@ function useChunkCatchup({
|
|
|
46991
46995
|
const buffered = [...chunkBuffer.current];
|
|
46992
46996
|
chunkBuffer.current = [];
|
|
46993
46997
|
buffered.sort((a, b) => {
|
|
46994
|
-
const seqA = a.chunk.sequenceId ??
|
|
46995
|
-
const seqB = b.chunk.sequenceId ??
|
|
46998
|
+
const seqA = a.chunk.sequenceId ?? Number.MAX_SAFE_INTEGER;
|
|
46999
|
+
const seqB = b.chunk.sequenceId ?? Number.MAX_SAFE_INTEGER;
|
|
46996
47000
|
return seqA - seqB;
|
|
46997
47001
|
});
|
|
46998
47002
|
buffered.forEach(({ chunk, messageType }) => {
|
|
@@ -47007,9 +47011,14 @@ function useChunkCatchup({
|
|
|
47007
47011
|
return;
|
|
47008
47012
|
}
|
|
47009
47013
|
if (hasCompletedInitialCatchup.current) {
|
|
47014
|
+
if (bufferUntilInitialCatchupComplete.current) {
|
|
47015
|
+
bufferUntilInitialCatchupComplete.current = false;
|
|
47016
|
+
flushBufferedRealtimeChunks();
|
|
47017
|
+
}
|
|
47010
47018
|
return;
|
|
47011
47019
|
}
|
|
47012
47020
|
if (fetchingInProgress.current) {
|
|
47021
|
+
pendingCatchupRef.current = { dialogId: dialogId2, fromSequenceId: fromSequenceId ?? lastSequenceId.current };
|
|
47013
47022
|
return;
|
|
47014
47023
|
}
|
|
47015
47024
|
if (lastFetchParams.current && lastFetchParams.current.dialogId === dialogId2 && lastFetchParams.current.fromSequenceId === fromSequenceId) {
|
|
@@ -47026,7 +47035,8 @@ function useChunkCatchup({
|
|
|
47026
47035
|
try {
|
|
47027
47036
|
const chunkPromises = chatTypes2.map(async (chatType) => {
|
|
47028
47037
|
try {
|
|
47029
|
-
const
|
|
47038
|
+
const typeFromSequenceId = fromSequenceId === void 0 ? void 0 : lastSequenceIdByType.current.get(getChatTypeMessageType(chatType)) ?? null;
|
|
47039
|
+
const chunks = await fetchChunks2(dialogId2, chatType, typeFromSequenceId);
|
|
47030
47040
|
const messageType = getChatTypeMessageType(chatType);
|
|
47031
47041
|
return chunks.map((chunk) => ({ chunk, messageType }));
|
|
47032
47042
|
} catch (error) {
|
|
@@ -47046,49 +47056,66 @@ function useChunkCatchup({
|
|
|
47046
47056
|
chunkBuffer.current = [];
|
|
47047
47057
|
const allChunks = [...allCatchupChunks, ...bufferedNatsChunks];
|
|
47048
47058
|
allChunks.sort((a, b) => {
|
|
47049
|
-
const seqA = a.chunk.sequenceId ??
|
|
47050
|
-
const seqB = b.chunk.sequenceId ??
|
|
47059
|
+
const seqA = a.chunk.sequenceId ?? Number.MAX_SAFE_INTEGER;
|
|
47060
|
+
const seqB = b.chunk.sequenceId ?? Number.MAX_SAFE_INTEGER;
|
|
47051
47061
|
return seqA - seqB;
|
|
47052
47062
|
});
|
|
47053
47063
|
const uniqueAllChunks = [];
|
|
47054
47064
|
const seenInBatch = /* @__PURE__ */ new Set();
|
|
47055
47065
|
for (const item of allChunks) {
|
|
47056
|
-
const
|
|
47057
|
-
if (
|
|
47058
|
-
|
|
47059
|
-
|
|
47060
|
-
|
|
47061
|
-
let lastMessageStartSeqId = null;
|
|
47062
|
-
let lastMessageEndSeqId = null;
|
|
47063
|
-
for (let i = uniqueAllChunks.length - 1; i >= 0; i--) {
|
|
47064
|
-
const seq = uniqueAllChunks[i].chunk.sequenceId;
|
|
47065
|
-
if (uniqueAllChunks[i].chunk.type === MESSAGE_TYPE.MESSAGE_END && seq !== void 0 && seq !== null) {
|
|
47066
|
-
lastMessageEndSeqId = seq;
|
|
47067
|
-
break;
|
|
47066
|
+
const hasSeq = item.chunk.sequenceId !== void 0 && item.chunk.sequenceId !== null;
|
|
47067
|
+
if (hasSeq) {
|
|
47068
|
+
const k = makeBatchDedupKey(item);
|
|
47069
|
+
if (seenInBatch.has(k)) continue;
|
|
47070
|
+
seenInBatch.add(k);
|
|
47068
47071
|
}
|
|
47072
|
+
uniqueAllChunks.push(item);
|
|
47069
47073
|
}
|
|
47070
|
-
|
|
47071
|
-
|
|
47072
|
-
|
|
47073
|
-
|
|
47074
|
-
|
|
47075
|
-
|
|
47074
|
+
const hasNoSeq = (item) => item.chunk.sequenceId === void 0 || item.chunk.sequenceId === null;
|
|
47075
|
+
const byType = /* @__PURE__ */ new Map();
|
|
47076
|
+
for (const item of uniqueAllChunks) {
|
|
47077
|
+
const list = byType.get(item.messageType);
|
|
47078
|
+
if (list) list.push(item);
|
|
47079
|
+
else byType.set(item.messageType, [item]);
|
|
47080
|
+
}
|
|
47081
|
+
const chunksToProcess = [];
|
|
47082
|
+
for (const items of byType.values()) {
|
|
47083
|
+
let lastMessageStartSeqId = null;
|
|
47084
|
+
let lastMessageEndSeqId = null;
|
|
47085
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
47086
|
+
const seq = items[i].chunk.sequenceId;
|
|
47087
|
+
if (items[i].chunk.type === MESSAGE_TYPE.MESSAGE_END && seq !== void 0 && seq !== null) {
|
|
47088
|
+
lastMessageEndSeqId = seq;
|
|
47076
47089
|
break;
|
|
47077
47090
|
}
|
|
47078
47091
|
}
|
|
47092
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
47093
|
+
const chunk = items[i].chunk;
|
|
47094
|
+
const seq = chunk.sequenceId;
|
|
47095
|
+
if (chunk.type === MESSAGE_TYPE.MESSAGE_START && seq !== void 0 && seq !== null) {
|
|
47096
|
+
if (lastMessageEndSeqId === null || seq > lastMessageEndSeqId) {
|
|
47097
|
+
lastMessageStartSeqId = seq;
|
|
47098
|
+
break;
|
|
47099
|
+
}
|
|
47100
|
+
}
|
|
47101
|
+
}
|
|
47102
|
+
if (lastMessageStartSeqId !== null) {
|
|
47103
|
+
chunksToProcess.push(
|
|
47104
|
+
...items.filter((item) => hasNoSeq(item) || item.chunk.sequenceId >= lastMessageStartSeqId)
|
|
47105
|
+
);
|
|
47106
|
+
} else if (lastMessageEndSeqId !== null) {
|
|
47107
|
+
chunksToProcess.push(
|
|
47108
|
+
...items.filter((item) => hasNoSeq(item) || item.chunk.sequenceId > lastMessageEndSeqId)
|
|
47109
|
+
);
|
|
47110
|
+
} else {
|
|
47111
|
+
chunksToProcess.push(...items);
|
|
47112
|
+
}
|
|
47079
47113
|
}
|
|
47080
|
-
|
|
47081
|
-
|
|
47082
|
-
|
|
47083
|
-
|
|
47084
|
-
|
|
47085
|
-
} else if (lastMessageEndSeqId !== null) {
|
|
47086
|
-
chunksToProcess = uniqueAllChunks.filter(
|
|
47087
|
-
(item) => item.chunk.sequenceId !== void 0 && item.chunk.sequenceId > lastMessageEndSeqId
|
|
47088
|
-
);
|
|
47089
|
-
} else {
|
|
47090
|
-
chunksToProcess = uniqueAllChunks;
|
|
47091
|
-
}
|
|
47114
|
+
chunksToProcess.sort((a, b) => {
|
|
47115
|
+
const seqA = a.chunk.sequenceId ?? Number.MAX_SAFE_INTEGER;
|
|
47116
|
+
const seqB = b.chunk.sequenceId ?? Number.MAX_SAFE_INTEGER;
|
|
47117
|
+
return seqA - seqB;
|
|
47118
|
+
});
|
|
47092
47119
|
chunksToProcess.forEach(({ chunk, messageType }) => {
|
|
47093
47120
|
if (chunk.sequenceId !== void 0 && chunk.sequenceId !== null) {
|
|
47094
47121
|
const chunkType = typeof chunk.type === "string" ? chunk.type : "";
|
|
@@ -47096,6 +47123,10 @@ function useChunkCatchup({
|
|
|
47096
47123
|
if (processedSequenceKeys.current.has(key)) return;
|
|
47097
47124
|
processedSequenceKeys.current.add(key);
|
|
47098
47125
|
lastSequenceId.current = chunk.sequenceId;
|
|
47126
|
+
const prevTypeSeq = lastSequenceIdByType.current.get(messageType);
|
|
47127
|
+
if (prevTypeSeq === void 0 || chunk.sequenceId > prevTypeSeq) {
|
|
47128
|
+
lastSequenceIdByType.current.set(messageType, chunk.sequenceId);
|
|
47129
|
+
}
|
|
47099
47130
|
}
|
|
47100
47131
|
onChunkReceivedRef.current(chunk, messageType);
|
|
47101
47132
|
});
|
|
@@ -47104,26 +47135,55 @@ function useChunkCatchup({
|
|
|
47104
47135
|
} catch (error) {
|
|
47105
47136
|
console.error("Error during chunk catchup:", error);
|
|
47106
47137
|
} finally {
|
|
47107
|
-
|
|
47108
|
-
|
|
47109
|
-
|
|
47110
|
-
|
|
47111
|
-
|
|
47138
|
+
if (dialogId2 !== dialogIdRef.current) {
|
|
47139
|
+
if (pendingCatchupRef.current?.dialogId === dialogId2) {
|
|
47140
|
+
pendingCatchupRef.current = null;
|
|
47141
|
+
}
|
|
47142
|
+
} else {
|
|
47143
|
+
fetchingInProgress.current = false;
|
|
47144
|
+
const pending = pendingCatchupRef.current;
|
|
47145
|
+
if (pending) {
|
|
47146
|
+
pendingCatchupRef.current = null;
|
|
47147
|
+
if (pending.dialogId === dialogId2) {
|
|
47148
|
+
hasCompletedInitialCatchup.current = false;
|
|
47149
|
+
lastFetchParams.current = null;
|
|
47150
|
+
bufferUntilInitialCatchupComplete.current = true;
|
|
47151
|
+
try {
|
|
47152
|
+
await catchUpChunksRef.current?.(pending.fromSequenceId);
|
|
47153
|
+
} catch (rerunError) {
|
|
47154
|
+
console.error("Queued catch-up re-run failed:", rerunError);
|
|
47155
|
+
}
|
|
47156
|
+
} else if (bufferUntilInitialCatchupComplete.current) {
|
|
47157
|
+
bufferUntilInitialCatchupComplete.current = false;
|
|
47158
|
+
hasCompletedInitialCatchup.current = true;
|
|
47159
|
+
flushBufferedRealtimeChunks();
|
|
47160
|
+
}
|
|
47161
|
+
} else if (bufferUntilInitialCatchupComplete.current) {
|
|
47162
|
+
bufferUntilInitialCatchupComplete.current = false;
|
|
47163
|
+
hasCompletedInitialCatchup.current = true;
|
|
47164
|
+
flushBufferedRealtimeChunks();
|
|
47165
|
+
}
|
|
47112
47166
|
}
|
|
47113
47167
|
}
|
|
47114
47168
|
}, [flushBufferedRealtimeChunks]);
|
|
47169
|
+
const catchUpChunksRef = useRef64(null);
|
|
47170
|
+
catchUpChunksRef.current = catchUpChunks;
|
|
47115
47171
|
const resetChunkTracking = useCallback46(() => {
|
|
47116
47172
|
processedSequenceKeys.current.clear();
|
|
47117
47173
|
lastSequenceId.current = null;
|
|
47174
|
+
lastSequenceIdByType.current.clear();
|
|
47118
47175
|
fetchingInProgress.current = false;
|
|
47119
47176
|
lastFetchParams.current = null;
|
|
47177
|
+
pendingCatchupRef.current = null;
|
|
47120
47178
|
chunkBuffer.current = [];
|
|
47121
47179
|
bufferUntilInitialCatchupComplete.current = false;
|
|
47122
47180
|
hasCompletedInitialCatchup.current = false;
|
|
47123
47181
|
}, []);
|
|
47124
47182
|
const startInitialBuffering = useCallback46(() => {
|
|
47125
|
-
|
|
47126
|
-
|
|
47183
|
+
if (!bufferUntilInitialCatchupComplete.current) {
|
|
47184
|
+
chunkBuffer.current = [];
|
|
47185
|
+
bufferUntilInitialCatchupComplete.current = true;
|
|
47186
|
+
}
|
|
47127
47187
|
hasCompletedInitialCatchup.current = false;
|
|
47128
47188
|
}, []);
|
|
47129
47189
|
const isBufferingActive = useCallback46(() => bufferUntilInitialCatchupComplete.current, []);
|
|
@@ -47132,8 +47192,10 @@ function useChunkCatchup({
|
|
|
47132
47192
|
const fromSeq = lastSequenceId.current;
|
|
47133
47193
|
hasCompletedInitialCatchup.current = false;
|
|
47134
47194
|
lastFetchParams.current = null;
|
|
47135
|
-
bufferUntilInitialCatchupComplete.current
|
|
47136
|
-
|
|
47195
|
+
if (!bufferUntilInitialCatchupComplete.current) {
|
|
47196
|
+
chunkBuffer.current = [];
|
|
47197
|
+
bufferUntilInitialCatchupComplete.current = true;
|
|
47198
|
+
}
|
|
47137
47199
|
await catchUpChunks(fromSeq);
|
|
47138
47200
|
}, [catchUpChunks]);
|
|
47139
47201
|
return {
|
|
@@ -47333,6 +47395,10 @@ function useJetStreamDialogSubscription({
|
|
|
47333
47395
|
}
|
|
47334
47396
|
};
|
|
47335
47397
|
}, [enabled, wsUrl]);
|
|
47398
|
+
useEffect79(() => {
|
|
47399
|
+
highestStreamSeqRef.current = null;
|
|
47400
|
+
setCurrentStreamSeq(null);
|
|
47401
|
+
}, [dialogId]);
|
|
47336
47402
|
useEffect79(() => {
|
|
47337
47403
|
if (!enabled || !dialogId || !isConnected) {
|
|
47338
47404
|
if (subscriptionRef.current) {
|
|
@@ -47416,10 +47482,6 @@ function useJetStreamDialogSubscription({
|
|
|
47416
47482
|
setIsSubscribed(false);
|
|
47417
47483
|
};
|
|
47418
47484
|
}, [enabled, dialogId, isConnected, streamName, topic, reconnectionCount]);
|
|
47419
|
-
useEffect79(() => {
|
|
47420
|
-
highestStreamSeqRef.current = null;
|
|
47421
|
-
setCurrentStreamSeq(null);
|
|
47422
|
-
}, [dialogId]);
|
|
47423
47485
|
return { isConnected, isSubscribed, reconnectionCount, currentStreamSeq };
|
|
47424
47486
|
}
|
|
47425
47487
|
|
|
@@ -47560,6 +47622,8 @@ function useNatsDialogSubscription({
|
|
|
47560
47622
|
};
|
|
47561
47623
|
}, [enabled, wsUrl]);
|
|
47562
47624
|
const topicsKey = topics.join(",");
|
|
47625
|
+
const topicsRef = useRef66(topics);
|
|
47626
|
+
topicsRef.current = topics;
|
|
47563
47627
|
const lastSubscribedDialogIdRef = useRef66(null);
|
|
47564
47628
|
const isConnectedRef = useRef66(isConnected);
|
|
47565
47629
|
useEffect80(() => {
|
|
@@ -47619,7 +47683,7 @@ function useNatsDialogSubscription({
|
|
|
47619
47683
|
} catch {
|
|
47620
47684
|
}
|
|
47621
47685
|
};
|
|
47622
|
-
|
|
47686
|
+
topicsRef.current.forEach((topic) => {
|
|
47623
47687
|
const subscription = client.subscribeBytes(
|
|
47624
47688
|
`chat.${dialogId}.${topic}`,
|
|
47625
47689
|
handleMessage(topic),
|
|
@@ -47647,7 +47711,7 @@ function useNatsDialogSubscription({
|
|
|
47647
47711
|
lastSubscribedDialogIdRef.current = null;
|
|
47648
47712
|
abortControllerRef.current = null;
|
|
47649
47713
|
};
|
|
47650
|
-
}, [enabled, dialogId, topicsKey
|
|
47714
|
+
}, [enabled, dialogId, topicsKey]);
|
|
47651
47715
|
useEffect80(() => {
|
|
47652
47716
|
if (!enabled || !currentDialogIdRef.current || !isConnected) {
|
|
47653
47717
|
return;
|
|
@@ -47670,7 +47734,7 @@ function useNatsDialogSubscription({
|
|
|
47670
47734
|
} catch {
|
|
47671
47735
|
}
|
|
47672
47736
|
};
|
|
47673
|
-
|
|
47737
|
+
topicsRef.current.forEach((topic) => {
|
|
47674
47738
|
const subscription = client.subscribeBytes(
|
|
47675
47739
|
`chat.${dialogId2}.${topic}`,
|
|
47676
47740
|
handleMessage(topic),
|
|
@@ -47684,7 +47748,7 @@ function useNatsDialogSubscription({
|
|
|
47684
47748
|
} else if (subscriptionRefs.current.size > 0) {
|
|
47685
47749
|
setIsSubscribed(true);
|
|
47686
47750
|
}
|
|
47687
|
-
}, [isConnected, enabled,
|
|
47751
|
+
}, [isConnected, enabled, topicsKey]);
|
|
47688
47752
|
return { isConnected, isSubscribed, reconnectionCount };
|
|
47689
47753
|
}
|
|
47690
47754
|
function buildNatsWsUrl(apiBaseUrl, options) {
|
|
@@ -48045,6 +48109,10 @@ var MessageSegmentAccumulator = class {
|
|
|
48045
48109
|
const hasCall = seg.data.toolCalls.some((c) => c.toolExecutionRequestId === execId);
|
|
48046
48110
|
if (!hasCall) return seg;
|
|
48047
48111
|
const prev = seg.data.executions?.[execId];
|
|
48112
|
+
if (toolData.type === "EXECUTING_TOOL" && prev?.status === "done") {
|
|
48113
|
+
matched = true;
|
|
48114
|
+
return seg;
|
|
48115
|
+
}
|
|
48048
48116
|
const next = toolData.type === "EXECUTED_TOOL" ? { status: "done", result: toolData.result, success: toolData.success } : { status: "executing", result: prev?.result, success: prev?.success };
|
|
48049
48117
|
matched = true;
|
|
48050
48118
|
return {
|
|
@@ -48508,6 +48576,16 @@ function useRealtimeChunkProcessor(options) {
|
|
|
48508
48576
|
explanation: escalatedData.explanation,
|
|
48509
48577
|
approvalType: escalatedData.approvalType
|
|
48510
48578
|
});
|
|
48579
|
+
const emitResolved = (segments) => {
|
|
48580
|
+
if (isInStreamRef.current) {
|
|
48581
|
+
emitSegments(segments);
|
|
48582
|
+
return;
|
|
48583
|
+
}
|
|
48584
|
+
const delta = segments.filter(
|
|
48585
|
+
(s) => s.type === "approval_request" && s.data.requestId === requestId || s.type === "approval_batch" && s.data.approvalRequestId === requestId
|
|
48586
|
+
);
|
|
48587
|
+
emitSegments(delta, { append: true });
|
|
48588
|
+
};
|
|
48511
48589
|
if (escalatedData.toolCalls && escalatedData.toolCalls.length > 0) {
|
|
48512
48590
|
if (batchApprovalsEnabled) {
|
|
48513
48591
|
const segments = accumulator.addApprovalBatch(
|
|
@@ -48518,7 +48596,7 @@ function useRealtimeChunkProcessor(options) {
|
|
|
48518
48596
|
void 0,
|
|
48519
48597
|
resolvedByName
|
|
48520
48598
|
);
|
|
48521
|
-
|
|
48599
|
+
emitResolved(segments);
|
|
48522
48600
|
} else {
|
|
48523
48601
|
let segments = accumulator.getSegments();
|
|
48524
48602
|
for (const call of escalatedData.toolCalls) {
|
|
@@ -48531,7 +48609,7 @@ function useRealtimeChunkProcessor(options) {
|
|
|
48531
48609
|
status
|
|
48532
48610
|
);
|
|
48533
48611
|
}
|
|
48534
|
-
|
|
48612
|
+
emitResolved(segments);
|
|
48535
48613
|
}
|
|
48536
48614
|
} else {
|
|
48537
48615
|
const segments = accumulator.addApprovalRequest(
|
|
@@ -48541,7 +48619,7 @@ function useRealtimeChunkProcessor(options) {
|
|
|
48541
48619
|
escalatedData.approvalType,
|
|
48542
48620
|
status
|
|
48543
48621
|
);
|
|
48544
|
-
|
|
48622
|
+
emitResolved(segments);
|
|
48545
48623
|
}
|
|
48546
48624
|
} else {
|
|
48547
48625
|
accumulator.updateApprovalStatus(requestId, status, resolvedByName);
|
|
@@ -48621,6 +48699,8 @@ function useRealtimeChunkProcessor(options) {
|
|
|
48621
48699
|
hasInitializedWithData.current = false;
|
|
48622
48700
|
sawDirectMessageRef.current = false;
|
|
48623
48701
|
directTeardownFiredRef.current = false;
|
|
48702
|
+
isInStreamRef.current = false;
|
|
48703
|
+
hasEverStreamedRef.current = false;
|
|
48624
48704
|
}, []);
|
|
48625
48705
|
const updateApprovalStatus = useCallback47(
|
|
48626
48706
|
(requestId, status, resolvedByName) => {
|
|
@@ -50151,7 +50231,15 @@ function processHistoricalMessages(messages, options = {}) {
|
|
|
50151
50231
|
onReject,
|
|
50152
50232
|
chatTypeFilter,
|
|
50153
50233
|
approvalStatuses = {},
|
|
50154
|
-
|
|
50234
|
+
// An omitted option means "display every approval type" — the original
|
|
50235
|
+
// history semantics. Deliberately NOT defaulted to the realtime
|
|
50236
|
+
// processor's ['CLIENT']: consumers that pass a wider list to their
|
|
50237
|
+
// realtime processor but omit it on the history path would silently lose
|
|
50238
|
+
// pending non-CLIENT approval cards on every reload/reconnect refetch
|
|
50239
|
+
// (they also ignore `escalatedApprovals`). Realtime/history parity is
|
|
50240
|
+
// opt-in: pass the same explicit list to both.
|
|
50241
|
+
displayApprovalTypes,
|
|
50242
|
+
batchApprovalsEnabled
|
|
50155
50243
|
} = options;
|
|
50156
50244
|
const processedMessages = [];
|
|
50157
50245
|
const accumulator = createMessageSegmentAccumulator({ onApprove, onReject });
|
|
@@ -50216,7 +50304,13 @@ function processHistoricalMessages(messages, options = {}) {
|
|
|
50216
50304
|
}
|
|
50217
50305
|
lastAssistantId = msg.id;
|
|
50218
50306
|
messageDataArray.forEach((data) => {
|
|
50219
|
-
processMessageData(
|
|
50307
|
+
processMessageData(
|
|
50308
|
+
data,
|
|
50309
|
+
accumulator,
|
|
50310
|
+
approvalStatuses,
|
|
50311
|
+
{ displayApprovalTypes, batchApprovalsEnabled },
|
|
50312
|
+
escalatedApprovals
|
|
50313
|
+
);
|
|
50220
50314
|
});
|
|
50221
50315
|
const nextMsg = messages[index + 1];
|
|
50222
50316
|
const isLastMessage = index === messages.length - 1;
|
|
@@ -50440,7 +50534,7 @@ function extractErrorMessages(messages, options = {}) {
|
|
|
50440
50534
|
return errorMessages;
|
|
50441
50535
|
}
|
|
50442
50536
|
function processHistoricalMessagesWithErrors(messages, options = {}) {
|
|
50443
|
-
const { chatTypeFilter, assistantName = "Fae", assistantType = "fae", assistantAvatar, onApprove, onReject, approvalStatuses = {}, displayApprovalTypes } = options;
|
|
50537
|
+
const { chatTypeFilter, assistantName = "Fae", assistantType = "fae", assistantAvatar, onApprove, onReject, approvalStatuses = {}, displayApprovalTypes, batchApprovalsEnabled } = options;
|
|
50444
50538
|
const processedMessages = [];
|
|
50445
50539
|
const accumulator = createMessageSegmentAccumulator({ onApprove, onReject });
|
|
50446
50540
|
const escalatedApprovals = /* @__PURE__ */ new Map();
|
|
@@ -50504,7 +50598,13 @@ function processHistoricalMessagesWithErrors(messages, options = {}) {
|
|
|
50504
50598
|
}
|
|
50505
50599
|
lastAssistantId = msg.id;
|
|
50506
50600
|
messageDataArray.forEach((data) => {
|
|
50507
|
-
processMessageData(
|
|
50601
|
+
processMessageData(
|
|
50602
|
+
data,
|
|
50603
|
+
accumulator,
|
|
50604
|
+
approvalStatuses,
|
|
50605
|
+
{ displayApprovalTypes, batchApprovalsEnabled },
|
|
50606
|
+
escalatedApprovals
|
|
50607
|
+
);
|
|
50508
50608
|
});
|
|
50509
50609
|
const nextMsg = messages[index + 1];
|
|
50510
50610
|
const isLastMessage = index === messages.length - 1;
|
|
@@ -50533,6 +50633,65 @@ function processHistoricalMessagesWithErrors(messages, options = {}) {
|
|
|
50533
50633
|
};
|
|
50534
50634
|
}
|
|
50535
50635
|
|
|
50636
|
+
// src/components/chat/utils/extract-incomplete-message-state.ts
|
|
50637
|
+
function extractIncompleteMessageState(lastMessage) {
|
|
50638
|
+
if (!lastMessage || lastMessage.role !== "assistant" || typeof lastMessage.content === "string") {
|
|
50639
|
+
return void 0;
|
|
50640
|
+
}
|
|
50641
|
+
const segments = lastMessage.content;
|
|
50642
|
+
const pendingApprovals = /* @__PURE__ */ new Map();
|
|
50643
|
+
const executingTools = /* @__PURE__ */ new Map();
|
|
50644
|
+
let hasIncompleteState = false;
|
|
50645
|
+
segments.forEach((segment) => {
|
|
50646
|
+
switch (segment.type) {
|
|
50647
|
+
case "tool_execution":
|
|
50648
|
+
if (segment.data.type === "EXECUTING_TOOL") {
|
|
50649
|
+
const toolKey = segment.data.toolExecutionRequestId || `${segment.data.integratedToolType}-${segment.data.toolFunction}`;
|
|
50650
|
+
executingTools.set(toolKey, {
|
|
50651
|
+
integratedToolType: segment.data.integratedToolType,
|
|
50652
|
+
toolFunction: segment.data.toolFunction,
|
|
50653
|
+
toolTitle: segment.data.toolTitle,
|
|
50654
|
+
parameters: segment.data.parameters
|
|
50655
|
+
});
|
|
50656
|
+
hasIncompleteState = true;
|
|
50657
|
+
}
|
|
50658
|
+
break;
|
|
50659
|
+
case "approval_request":
|
|
50660
|
+
if (segment.status === "pending" && segment.data.requestId) {
|
|
50661
|
+
pendingApprovals.set(segment.data.requestId, {
|
|
50662
|
+
command: segment.data.command,
|
|
50663
|
+
explanation: segment.data.explanation,
|
|
50664
|
+
approvalType: segment.data.approvalType || "CLIENT"
|
|
50665
|
+
});
|
|
50666
|
+
hasIncompleteState = true;
|
|
50667
|
+
}
|
|
50668
|
+
break;
|
|
50669
|
+
case "approval_batch": {
|
|
50670
|
+
const allDone = !!segment.data.executions && segment.data.toolCalls.every(
|
|
50671
|
+
(c) => segment.data.executions?.[c.toolExecutionRequestId]?.status === "done"
|
|
50672
|
+
);
|
|
50673
|
+
if (segment.status !== "rejected" && !allDone) {
|
|
50674
|
+
hasIncompleteState = true;
|
|
50675
|
+
}
|
|
50676
|
+
break;
|
|
50677
|
+
}
|
|
50678
|
+
case "context_compaction":
|
|
50679
|
+
if (segment.status === "started") {
|
|
50680
|
+
hasIncompleteState = true;
|
|
50681
|
+
}
|
|
50682
|
+
break;
|
|
50683
|
+
}
|
|
50684
|
+
});
|
|
50685
|
+
if (!hasIncompleteState) {
|
|
50686
|
+
return void 0;
|
|
50687
|
+
}
|
|
50688
|
+
return {
|
|
50689
|
+
existingSegments: segments,
|
|
50690
|
+
pendingApprovals: pendingApprovals.size > 0 ? pendingApprovals : void 0,
|
|
50691
|
+
executingTools: executingTools.size > 0 ? executingTools : void 0
|
|
50692
|
+
};
|
|
50693
|
+
}
|
|
50694
|
+
|
|
50536
50695
|
// src/components/chat/hooks/use-nats-chat-adapter.ts
|
|
50537
50696
|
function nextId(role) {
|
|
50538
50697
|
return `${role}-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
|
|
@@ -50555,6 +50714,110 @@ function updateTrailingAssistant(prev, segments) {
|
|
|
50555
50714
|
{ ...last, segments }
|
|
50556
50715
|
];
|
|
50557
50716
|
}
|
|
50717
|
+
var CONTENT_DEDUP_WINDOW = 4;
|
|
50718
|
+
var SYSTEM_DEDUP_WINDOW = 10;
|
|
50719
|
+
function hasRecentMessage(prev, predicate, window2) {
|
|
50720
|
+
const start = Math.max(0, prev.length - window2);
|
|
50721
|
+
for (let i = prev.length - 1; i >= start; i--) {
|
|
50722
|
+
if (predicate(prev[i])) return true;
|
|
50723
|
+
}
|
|
50724
|
+
return false;
|
|
50725
|
+
}
|
|
50726
|
+
function appendToTrailingAssistant(prev, segments) {
|
|
50727
|
+
if (segments.length === 0) return prev;
|
|
50728
|
+
const last = prev[prev.length - 1];
|
|
50729
|
+
if (!last || last.role !== "assistant") {
|
|
50730
|
+
return [
|
|
50731
|
+
...prev,
|
|
50732
|
+
{ id: nextId("assistant"), role: "assistant", content: "", segments }
|
|
50733
|
+
];
|
|
50734
|
+
}
|
|
50735
|
+
const merged = [...last.segments ?? []];
|
|
50736
|
+
for (const seg of segments) {
|
|
50737
|
+
const tail = merged[merged.length - 1];
|
|
50738
|
+
if (seg.type === "text" && tail?.type === "text") {
|
|
50739
|
+
merged[merged.length - 1] = { type: "text", text: tail.text + seg.text };
|
|
50740
|
+
} else if (seg.type === "thinking" && tail?.type === "thinking") {
|
|
50741
|
+
merged[merged.length - 1] = { type: "thinking", text: tail.text + seg.text };
|
|
50742
|
+
} else if (seg.type === "approval_batch") {
|
|
50743
|
+
const idx = merged.findIndex(
|
|
50744
|
+
(m) => m.type === "approval_batch" && m.data.approvalRequestId === seg.data.approvalRequestId
|
|
50745
|
+
);
|
|
50746
|
+
if (idx !== -1) merged[idx] = seg;
|
|
50747
|
+
else merged.push(seg);
|
|
50748
|
+
} else if (seg.type === "approval_request") {
|
|
50749
|
+
const idx = merged.findIndex(
|
|
50750
|
+
(m) => m.type === "approval_request" && m.data.requestId === seg.data.requestId && m.data.command === seg.data.command
|
|
50751
|
+
);
|
|
50752
|
+
if (idx !== -1) merged[idx] = seg;
|
|
50753
|
+
else merged.push(seg);
|
|
50754
|
+
} else {
|
|
50755
|
+
merged.push(seg);
|
|
50756
|
+
}
|
|
50757
|
+
}
|
|
50758
|
+
return [...prev.slice(0, -1), { ...last, segments: merged }];
|
|
50759
|
+
}
|
|
50760
|
+
function upsertTrailingCompaction(prev, segments) {
|
|
50761
|
+
const compaction = [...segments].reverse().find((s) => s.type === "context_compaction");
|
|
50762
|
+
if (!compaction) return prev;
|
|
50763
|
+
const last = prev[prev.length - 1];
|
|
50764
|
+
if (!last || last.role !== "assistant") {
|
|
50765
|
+
return [
|
|
50766
|
+
...prev,
|
|
50767
|
+
{ id: nextId("assistant"), role: "assistant", content: "", segments: [compaction] }
|
|
50768
|
+
];
|
|
50769
|
+
}
|
|
50770
|
+
const existing = last.segments ?? [];
|
|
50771
|
+
const startedIdx = existing.map((s) => s.type === "context_compaction" && s.status === "started").lastIndexOf(true);
|
|
50772
|
+
const merged = startedIdx !== -1 ? existing.map((s, i) => i === startedIdx ? compaction : s) : [...existing, compaction];
|
|
50773
|
+
return [...prev.slice(0, -1), { ...last, segments: merged }];
|
|
50774
|
+
}
|
|
50775
|
+
function applyToolExecutionToMessages(prev, segment) {
|
|
50776
|
+
const toolData = segment.data;
|
|
50777
|
+
const execId = toolData.toolExecutionRequestId;
|
|
50778
|
+
for (let i = prev.length - 1; i >= 0; i--) {
|
|
50779
|
+
const message2 = prev[i];
|
|
50780
|
+
if (message2.role !== "assistant" || !message2.segments) continue;
|
|
50781
|
+
for (let j = message2.segments.length - 1; j >= 0; j--) {
|
|
50782
|
+
const seg = message2.segments[j];
|
|
50783
|
+
if (execId && seg.type === "approval_batch" && seg.data.toolCalls.some((c) => c.toolExecutionRequestId === execId)) {
|
|
50784
|
+
const prevExec = seg.data.executions?.[execId];
|
|
50785
|
+
if (toolData.type === "EXECUTING_TOOL" && prevExec?.status === "done") {
|
|
50786
|
+
return prev;
|
|
50787
|
+
}
|
|
50788
|
+
const nextExec = toolData.type === "EXECUTED_TOOL" ? { status: "done", result: toolData.result, success: toolData.success } : { status: "executing", result: prevExec?.result, success: prevExec?.success };
|
|
50789
|
+
const nextSegments = [...message2.segments];
|
|
50790
|
+
nextSegments[j] = {
|
|
50791
|
+
...seg,
|
|
50792
|
+
data: { ...seg.data, executions: { ...seg.data.executions ?? {}, [execId]: nextExec } }
|
|
50793
|
+
};
|
|
50794
|
+
const next = [...prev];
|
|
50795
|
+
next[i] = { ...message2, segments: nextSegments };
|
|
50796
|
+
return next;
|
|
50797
|
+
}
|
|
50798
|
+
if (seg.type === "tool_execution") {
|
|
50799
|
+
const matches = execId ? seg.data.toolExecutionRequestId === execId : seg.data.type === "EXECUTING_TOOL" && seg.data.integratedToolType === toolData.integratedToolType && seg.data.toolFunction === toolData.toolFunction;
|
|
50800
|
+
if (!matches) continue;
|
|
50801
|
+
if (toolData.type === "EXECUTING_TOOL" && seg.data.type === "EXECUTED_TOOL") {
|
|
50802
|
+
return prev;
|
|
50803
|
+
}
|
|
50804
|
+
const nextSegments = [...message2.segments];
|
|
50805
|
+
nextSegments[j] = {
|
|
50806
|
+
type: "tool_execution",
|
|
50807
|
+
data: {
|
|
50808
|
+
...toolData,
|
|
50809
|
+
toolTitle: toolData.toolTitle ?? seg.data.toolTitle,
|
|
50810
|
+
parameters: toolData.parameters || seg.data.parameters
|
|
50811
|
+
}
|
|
50812
|
+
};
|
|
50813
|
+
const next = [...prev];
|
|
50814
|
+
next[i] = { ...message2, segments: nextSegments };
|
|
50815
|
+
return next;
|
|
50816
|
+
}
|
|
50817
|
+
}
|
|
50818
|
+
}
|
|
50819
|
+
return appendToTrailingAssistant(prev, [segment]);
|
|
50820
|
+
}
|
|
50558
50821
|
function mapProcessedToUnified(processed) {
|
|
50559
50822
|
const out = [];
|
|
50560
50823
|
for (const m of processed) {
|
|
@@ -50594,6 +50857,7 @@ function useNatsChatAdapter(config, options = {}) {
|
|
|
50594
50857
|
fetchChunks,
|
|
50595
50858
|
topics,
|
|
50596
50859
|
batchApprovalsEnabled,
|
|
50860
|
+
displayApprovalTypes,
|
|
50597
50861
|
fetchDialogs,
|
|
50598
50862
|
fetchDialogMessages,
|
|
50599
50863
|
createDialog: createDialogCallback,
|
|
@@ -50613,11 +50877,17 @@ function useNatsChatAdapter(config, options = {}) {
|
|
|
50613
50877
|
const isManagedMode = fetchDialogs !== void 0;
|
|
50614
50878
|
const [internalDialogId, setInternalDialogId] = useState116(null);
|
|
50615
50879
|
const dialogId = isManagedMode ? internalDialogId : controlledDialogId !== void 0 ? controlledDialogId : null;
|
|
50880
|
+
const currentDialogIdRef = useRef74(dialogId);
|
|
50881
|
+
currentDialogIdRef.current = dialogId;
|
|
50616
50882
|
const [messages, setMessages] = useState116([]);
|
|
50617
50883
|
const [streamingPhase, setStreamingPhase] = useState116("idle");
|
|
50618
50884
|
const streamingPhaseRef = useRef74(streamingPhase);
|
|
50619
50885
|
streamingPhaseRef.current = streamingPhase;
|
|
50620
|
-
const suppressAgentBusyRef = useRef74(
|
|
50886
|
+
const suppressAgentBusyRef = useRef74(0);
|
|
50887
|
+
const adoptTrailingAssistantRef = useRef74(false);
|
|
50888
|
+
const hasConnectedOnceRef = useRef74(false);
|
|
50889
|
+
const seenParticipantSeqsRef = useRef74(/* @__PURE__ */ new Set());
|
|
50890
|
+
const pendingEchoTextsRef = useRef74([]);
|
|
50621
50891
|
const [approvalStatuses, setApprovalStatuses] = useState116({});
|
|
50622
50892
|
const [dialogs, setDialogs] = useState116([]);
|
|
50623
50893
|
const [dialogsNextCursor, setDialogsNextCursor] = useState116(null);
|
|
@@ -50683,17 +50953,39 @@ function useNatsChatAdapter(config, options = {}) {
|
|
|
50683
50953
|
return handleRejectRef.current(requestId);
|
|
50684
50954
|
}, []);
|
|
50685
50955
|
const callbacksRef = useRef74({
|
|
50686
|
-
onSegmentsUpdate: (segments) => {
|
|
50956
|
+
onSegmentsUpdate: (segments, meta) => {
|
|
50957
|
+
if (meta?.append && meta.isCompacting) {
|
|
50958
|
+
setMessages((prev) => upsertTrailingCompaction(prev, segments));
|
|
50959
|
+
return;
|
|
50960
|
+
}
|
|
50961
|
+
if (meta?.append) {
|
|
50962
|
+
setMessages((prev) => appendToTrailingAssistant(prev, segments));
|
|
50963
|
+
return;
|
|
50964
|
+
}
|
|
50687
50965
|
setMessages((prev) => updateTrailingAssistant(prev, segments));
|
|
50688
50966
|
},
|
|
50689
|
-
onStreamStart: () =>
|
|
50967
|
+
onStreamStart: () => {
|
|
50968
|
+
setStreamingPhase("streaming");
|
|
50969
|
+
const adoptTail = adoptTrailingAssistantRef.current;
|
|
50970
|
+
adoptTrailingAssistantRef.current = false;
|
|
50971
|
+
setMessages((prev) => {
|
|
50972
|
+
const last = prev[prev.length - 1];
|
|
50973
|
+
if (!last || last.role !== "assistant" || adoptTail) return prev;
|
|
50974
|
+
const hasContent = (last.segments?.length ?? 0) > 0 || last.content !== "";
|
|
50975
|
+
if (!hasContent) return prev;
|
|
50976
|
+
return [
|
|
50977
|
+
...prev,
|
|
50978
|
+
{ id: nextId("assistant"), role: "assistant", content: "", segments: [] }
|
|
50979
|
+
];
|
|
50980
|
+
});
|
|
50981
|
+
},
|
|
50690
50982
|
onStreamEnd: () => setStreamingPhase("idle"),
|
|
50691
50983
|
// Agent is executing (approved) commands outside an open stream — keep
|
|
50692
50984
|
// the composer locked exactly like the in-stream phases. An open stream
|
|
50693
50985
|
// keeps ownership: only 'idle' upgrades to 'thinking'. Suppressed during
|
|
50694
50986
|
// initial catchup so a replayed dead tail can't lock a finished dialog.
|
|
50695
50987
|
onAgentBusy: () => {
|
|
50696
|
-
if (suppressAgentBusyRef.current) return;
|
|
50988
|
+
if (suppressAgentBusyRef.current > 0) return;
|
|
50697
50989
|
setStreamingPhase((p) => p === "idle" ? "thinking" : p);
|
|
50698
50990
|
},
|
|
50699
50991
|
// Terminal turn failures can arrive without a MESSAGE_END; unlock the
|
|
@@ -50708,27 +51000,171 @@ function useNatsChatAdapter(config, options = {}) {
|
|
|
50708
51000
|
provider: meta.providerName || null,
|
|
50709
51001
|
modelLabel: meta.modelDisplayName || meta.modelName || null,
|
|
50710
51002
|
contextWindowMaxTokens: meta.contextWindow || null
|
|
50711
|
-
})
|
|
51003
|
+
}),
|
|
51004
|
+
// Post-MESSAGE_END tool chunks (approved commands executing after the
|
|
51005
|
+
// approval bubble, async batch results). Routed through the cross-message
|
|
51006
|
+
// updater — the accumulator was reset at MESSAGE_END, so the old
|
|
51007
|
+
// fallthrough replaced the whole trailing bubble with one tool segment.
|
|
51008
|
+
onToolExecuted: (segment) => {
|
|
51009
|
+
setMessages((prev) => applyToolExecutionToMessages(prev, segment));
|
|
51010
|
+
},
|
|
51011
|
+
// Cross-message approval status flip. Wiring this also makes the
|
|
51012
|
+
// processor skip its cumulative re-emit for resolved approvals — which,
|
|
51013
|
+
// post-MESSAGE_END, was an empty array that blanked the trailing bubble.
|
|
51014
|
+
onApprovalResolved: (requestId, status, _approvalType, resolvedByName) => {
|
|
51015
|
+
setMessages((prev) => {
|
|
51016
|
+
let changed = false;
|
|
51017
|
+
const next = prev.map((m) => {
|
|
51018
|
+
if (m.role !== "assistant" || !m.segments) return m;
|
|
51019
|
+
let msgChanged = false;
|
|
51020
|
+
const segs = m.segments.map((s) => {
|
|
51021
|
+
if (s.type === "approval_request" && s.data.requestId === requestId && s.status !== status) {
|
|
51022
|
+
msgChanged = true;
|
|
51023
|
+
return { ...s, status };
|
|
51024
|
+
}
|
|
51025
|
+
if (s.type === "approval_batch" && s.data.approvalRequestId === requestId) {
|
|
51026
|
+
const nextResolvedBy = resolvedByName ?? s.resolvedByName;
|
|
51027
|
+
if (s.status === status && nextResolvedBy === s.resolvedByName) return s;
|
|
51028
|
+
msgChanged = true;
|
|
51029
|
+
return { ...s, status, resolvedByName: nextResolvedBy };
|
|
51030
|
+
}
|
|
51031
|
+
return s;
|
|
51032
|
+
});
|
|
51033
|
+
if (!msgChanged) return m;
|
|
51034
|
+
changed = true;
|
|
51035
|
+
return { ...m, segments: segs };
|
|
51036
|
+
});
|
|
51037
|
+
return changed ? next : prev;
|
|
51038
|
+
});
|
|
51039
|
+
setApprovalStatuses(
|
|
51040
|
+
(prev) => prev[requestId] === status ? prev : { ...prev, [requestId]: status }
|
|
51041
|
+
);
|
|
51042
|
+
},
|
|
51043
|
+
// MESSAGE_REQUEST echo — a user message from THIS or another session.
|
|
51044
|
+
onUserMessage: (text, meta) => {
|
|
51045
|
+
if (!text) return;
|
|
51046
|
+
const seq = meta?.streamSeq;
|
|
51047
|
+
if (typeof seq === "number") {
|
|
51048
|
+
if (seenParticipantSeqsRef.current.has(seq)) return;
|
|
51049
|
+
seenParticipantSeqsRef.current.add(seq);
|
|
51050
|
+
}
|
|
51051
|
+
if (meta?.ownerType !== "ADMIN") {
|
|
51052
|
+
const echoIdx = pendingEchoTextsRef.current.indexOf(text);
|
|
51053
|
+
if (echoIdx !== -1) {
|
|
51054
|
+
pendingEchoTextsRef.current.splice(echoIdx, 1);
|
|
51055
|
+
return;
|
|
51056
|
+
}
|
|
51057
|
+
}
|
|
51058
|
+
const authorType = meta?.ownerType === "ADMIN" ? "admin" : "user";
|
|
51059
|
+
setMessages((prev) => {
|
|
51060
|
+
if (typeof seq !== "number" && hasRecentMessage(
|
|
51061
|
+
prev,
|
|
51062
|
+
(m) => m.role === "user" && (m.authorType ?? "user") === authorType && m.content === text,
|
|
51063
|
+
CONTENT_DEDUP_WINDOW
|
|
51064
|
+
)) {
|
|
51065
|
+
return prev;
|
|
51066
|
+
}
|
|
51067
|
+
return [
|
|
51068
|
+
...prev,
|
|
51069
|
+
{
|
|
51070
|
+
id: nextId("user"),
|
|
51071
|
+
role: "user",
|
|
51072
|
+
content: text,
|
|
51073
|
+
...meta?.displayName ? { name: meta.displayName } : {},
|
|
51074
|
+
authorType,
|
|
51075
|
+
...meta?.contextItems && meta.contextItems.length > 0 ? {
|
|
51076
|
+
contextItems: meta.contextItems.map((ci) => ({
|
|
51077
|
+
type: ci.type,
|
|
51078
|
+
id: ci.id,
|
|
51079
|
+
label: ci.label ?? ci.id
|
|
51080
|
+
}))
|
|
51081
|
+
} : {}
|
|
51082
|
+
}
|
|
51083
|
+
];
|
|
51084
|
+
});
|
|
51085
|
+
},
|
|
51086
|
+
// Technician / admin direct message into the dialog.
|
|
51087
|
+
onDirectMessage: (text, meta) => {
|
|
51088
|
+
if (!text) return;
|
|
51089
|
+
const seq = meta?.streamSeq;
|
|
51090
|
+
if (typeof seq === "number") {
|
|
51091
|
+
if (seenParticipantSeqsRef.current.has(seq)) return;
|
|
51092
|
+
seenParticipantSeqsRef.current.add(seq);
|
|
51093
|
+
}
|
|
51094
|
+
setMessages((prev) => {
|
|
51095
|
+
if (typeof seq !== "number" && hasRecentMessage(
|
|
51096
|
+
prev,
|
|
51097
|
+
(m) => m.role === "user" && m.authorType === "admin" && m.content === text,
|
|
51098
|
+
CONTENT_DEDUP_WINDOW
|
|
51099
|
+
)) {
|
|
51100
|
+
return prev;
|
|
51101
|
+
}
|
|
51102
|
+
return [
|
|
51103
|
+
...prev,
|
|
51104
|
+
{
|
|
51105
|
+
id: `direct-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
|
51106
|
+
role: "user",
|
|
51107
|
+
content: text,
|
|
51108
|
+
name: meta?.displayName ?? "Admin",
|
|
51109
|
+
authorType: "admin"
|
|
51110
|
+
}
|
|
51111
|
+
];
|
|
51112
|
+
});
|
|
51113
|
+
},
|
|
51114
|
+
// System notice — rendered as a name-only row (same shape the history
|
|
51115
|
+
// processor produces via `pushStandaloneMessages`).
|
|
51116
|
+
onSystemMessage: (text, meta) => {
|
|
51117
|
+
if (!text) return;
|
|
51118
|
+
const seq = meta?.streamSeq;
|
|
51119
|
+
if (typeof seq === "number") {
|
|
51120
|
+
if (seenParticipantSeqsRef.current.has(seq)) return;
|
|
51121
|
+
seenParticipantSeqsRef.current.add(seq);
|
|
51122
|
+
}
|
|
51123
|
+
setMessages((prev) => {
|
|
51124
|
+
if (typeof seq !== "number" && hasRecentMessage(prev, (m) => m.authorType === "system" && m.name === text, SYSTEM_DEDUP_WINDOW)) {
|
|
51125
|
+
return prev;
|
|
51126
|
+
}
|
|
51127
|
+
return [
|
|
51128
|
+
...prev,
|
|
51129
|
+
{
|
|
51130
|
+
id: `system-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
|
|
51131
|
+
role: "user",
|
|
51132
|
+
content: "",
|
|
51133
|
+
name: text,
|
|
51134
|
+
authorType: "system"
|
|
51135
|
+
}
|
|
51136
|
+
];
|
|
51137
|
+
});
|
|
51138
|
+
}
|
|
50712
51139
|
});
|
|
50713
51140
|
const { processChunk, reset: resetAccumulator } = useRealtimeChunkProcessor({
|
|
50714
51141
|
callbacks: {
|
|
50715
|
-
onSegmentsUpdate: (segments) => callbacksRef.current.onSegmentsUpdate(segments),
|
|
51142
|
+
onSegmentsUpdate: (segments, meta) => callbacksRef.current.onSegmentsUpdate(segments, meta),
|
|
50716
51143
|
onStreamStart: () => callbacksRef.current.onStreamStart(),
|
|
50717
51144
|
onStreamEnd: () => callbacksRef.current.onStreamEnd(),
|
|
50718
51145
|
onAgentBusy: () => callbacksRef.current.onAgentBusy(),
|
|
50719
51146
|
onError: () => callbacksRef.current.onError(),
|
|
50720
51147
|
onTokenUsage: (data) => callbacksRef.current.onTokenUsage(data),
|
|
50721
51148
|
onMetadata: (meta) => callbacksRef.current.onMetadata(meta),
|
|
51149
|
+
onToolExecuted: (segment) => callbacksRef.current.onToolExecuted(segment),
|
|
51150
|
+
onApprovalResolved: (requestId, status, approvalType, resolvedByName) => callbacksRef.current.onApprovalResolved(requestId, status, approvalType, resolvedByName),
|
|
51151
|
+
onUserMessage: (text, meta) => callbacksRef.current.onUserMessage(text, meta),
|
|
51152
|
+
onDirectMessage: (text, meta) => callbacksRef.current.onDirectMessage(text, meta),
|
|
51153
|
+
onSystemMessage: (text, meta) => callbacksRef.current.onSystemMessage(text, meta),
|
|
50722
51154
|
onApprove: accumApprove,
|
|
50723
51155
|
onReject: accumReject
|
|
50724
51156
|
},
|
|
50725
|
-
batchApprovalsEnabled
|
|
51157
|
+
batchApprovalsEnabled,
|
|
51158
|
+
approvalStatuses,
|
|
51159
|
+
...displayApprovalTypes ? { displayApprovalTypes } : {}
|
|
50726
51160
|
});
|
|
50727
51161
|
const {
|
|
50728
51162
|
processChunk: catchupProcessChunk,
|
|
50729
51163
|
catchUpChunks,
|
|
50730
51164
|
startInitialBuffering,
|
|
50731
|
-
resetChunkTracking
|
|
51165
|
+
resetChunkTracking,
|
|
51166
|
+
resetAndCatchUp,
|
|
51167
|
+
isBufferingActive
|
|
50732
51168
|
} = useChunkCatchup({
|
|
50733
51169
|
dialogId: active ? dialogId : null,
|
|
50734
51170
|
onChunkReceived: (chunk) => processChunk(chunk),
|
|
@@ -50757,11 +51193,13 @@ function useNatsChatAdapter(config, options = {}) {
|
|
|
50757
51193
|
onApprove: accumApprove,
|
|
50758
51194
|
onReject: accumReject,
|
|
50759
51195
|
approvalStatuses,
|
|
50760
|
-
batchApprovalsEnabled
|
|
51196
|
+
batchApprovalsEnabled,
|
|
51197
|
+
...displayApprovalTypes ? { displayApprovalTypes } : {}
|
|
50761
51198
|
}
|
|
50762
51199
|
);
|
|
50763
51200
|
const unified = mapProcessedToUnified(rawProcessed);
|
|
50764
51201
|
if (cursor === void 0) {
|
|
51202
|
+
adoptTrailingAssistantRef.current = isBufferingActive() && extractIncompleteMessageState(rawProcessed[rawProcessed.length - 1]) !== void 0;
|
|
50765
51203
|
setMessages(unified);
|
|
50766
51204
|
} else {
|
|
50767
51205
|
setMessages((prev) => [...unified, ...prev]);
|
|
@@ -50785,8 +51223,10 @@ function useNatsChatAdapter(config, options = {}) {
|
|
|
50785
51223
|
chatTypeFilter,
|
|
50786
51224
|
approvalStatuses,
|
|
50787
51225
|
batchApprovalsEnabled,
|
|
51226
|
+
displayApprovalTypes,
|
|
50788
51227
|
accumApprove,
|
|
50789
|
-
accumReject
|
|
51228
|
+
accumReject,
|
|
51229
|
+
isBufferingActive
|
|
50790
51230
|
]
|
|
50791
51231
|
);
|
|
50792
51232
|
const prevDialogIdRef = useRef74(void 0);
|
|
@@ -50795,6 +51235,9 @@ function useNatsChatAdapter(config, options = {}) {
|
|
|
50795
51235
|
prevDialogIdRef.current = dialogId;
|
|
50796
51236
|
historyLoadSeqRef.current += 1;
|
|
50797
51237
|
resetAccumulator();
|
|
51238
|
+
adoptTrailingAssistantRef.current = false;
|
|
51239
|
+
seenParticipantSeqsRef.current.clear();
|
|
51240
|
+
pendingEchoTextsRef.current = [];
|
|
50798
51241
|
setMessages([]);
|
|
50799
51242
|
setMessagesNextCursor(null);
|
|
50800
51243
|
setDialogTokenUsage(null);
|
|
@@ -50806,13 +51249,16 @@ function useNatsChatAdapter(config, options = {}) {
|
|
|
50806
51249
|
}, [active, dialogId, loadDialogHistory, resetAccumulator]);
|
|
50807
51250
|
useEffect88(() => {
|
|
50808
51251
|
if (!active || !dialogId) return;
|
|
50809
|
-
suppressAgentBusyRef.current
|
|
51252
|
+
suppressAgentBusyRef.current += 1;
|
|
50810
51253
|
resetChunkTracking();
|
|
50811
51254
|
startInitialBuffering();
|
|
50812
51255
|
catchUpChunks().catch((err) => {
|
|
50813
51256
|
console.error("[useNatsChatAdapter] initial catchup failed:", err);
|
|
50814
51257
|
}).finally(() => {
|
|
50815
|
-
suppressAgentBusyRef.current =
|
|
51258
|
+
suppressAgentBusyRef.current = Math.max(0, suppressAgentBusyRef.current - 1);
|
|
51259
|
+
if (dialogId === currentDialogIdRef.current) {
|
|
51260
|
+
adoptTrailingAssistantRef.current = false;
|
|
51261
|
+
}
|
|
50816
51262
|
});
|
|
50817
51263
|
}, [active, dialogId, resetChunkTracking, startInitialBuffering, catchUpChunks]);
|
|
50818
51264
|
useNatsDialogSubscription({
|
|
@@ -50827,6 +51273,30 @@ function useNatsChatAdapter(config, options = {}) {
|
|
|
50827
51273
|
onEvent: (payload, messageType) => {
|
|
50828
51274
|
catchupProcessChunk(payload, messageType);
|
|
50829
51275
|
setConnectionState("connected");
|
|
51276
|
+
},
|
|
51277
|
+
onConnect: () => {
|
|
51278
|
+
if (!hasConnectedOnceRef.current) {
|
|
51279
|
+
hasConnectedOnceRef.current = true;
|
|
51280
|
+
return;
|
|
51281
|
+
}
|
|
51282
|
+
suppressAgentBusyRef.current += 1;
|
|
51283
|
+
startInitialBuffering();
|
|
51284
|
+
void (async () => {
|
|
51285
|
+
try {
|
|
51286
|
+
if (dialogId && fetchDialogMessages) {
|
|
51287
|
+
await loadDialogHistory(dialogId);
|
|
51288
|
+
}
|
|
51289
|
+
if (dialogId !== currentDialogIdRef.current) return;
|
|
51290
|
+
await resetAndCatchUp();
|
|
51291
|
+
} catch (err) {
|
|
51292
|
+
console.error("[useNatsChatAdapter] reconnect catchup failed:", err);
|
|
51293
|
+
} finally {
|
|
51294
|
+
suppressAgentBusyRef.current = Math.max(0, suppressAgentBusyRef.current - 1);
|
|
51295
|
+
if (dialogId === currentDialogIdRef.current) {
|
|
51296
|
+
adoptTrailingAssistantRef.current = false;
|
|
51297
|
+
}
|
|
51298
|
+
}
|
|
51299
|
+
})();
|
|
50830
51300
|
}
|
|
50831
51301
|
});
|
|
50832
51302
|
useEffect88(() => {
|
|
@@ -50878,6 +51348,8 @@ function useNatsChatAdapter(config, options = {}) {
|
|
|
50878
51348
|
const sendMessage = useCallback53(
|
|
50879
51349
|
async (text, sendOptions) => {
|
|
50880
51350
|
const hidden = sendOptions?.hidden ?? false;
|
|
51351
|
+
pendingEchoTextsRef.current.push(text);
|
|
51352
|
+
if (pendingEchoTextsRef.current.length > 5) pendingEchoTextsRef.current.shift();
|
|
50881
51353
|
setMessages((prev) => [
|
|
50882
51354
|
...prev,
|
|
50883
51355
|
{
|
|
@@ -51258,65 +51730,6 @@ function useUnifiedChat(options) {
|
|
|
51258
51730
|
);
|
|
51259
51731
|
}
|
|
51260
51732
|
|
|
51261
|
-
// src/components/chat/utils/extract-incomplete-message-state.ts
|
|
51262
|
-
function extractIncompleteMessageState(lastMessage) {
|
|
51263
|
-
if (!lastMessage || lastMessage.role !== "assistant" || typeof lastMessage.content === "string") {
|
|
51264
|
-
return void 0;
|
|
51265
|
-
}
|
|
51266
|
-
const segments = lastMessage.content;
|
|
51267
|
-
const pendingApprovals = /* @__PURE__ */ new Map();
|
|
51268
|
-
const executingTools = /* @__PURE__ */ new Map();
|
|
51269
|
-
let hasIncompleteState = false;
|
|
51270
|
-
segments.forEach((segment) => {
|
|
51271
|
-
switch (segment.type) {
|
|
51272
|
-
case "tool_execution":
|
|
51273
|
-
if (segment.data.type === "EXECUTING_TOOL") {
|
|
51274
|
-
const toolKey = segment.data.toolExecutionRequestId || `${segment.data.integratedToolType}-${segment.data.toolFunction}`;
|
|
51275
|
-
executingTools.set(toolKey, {
|
|
51276
|
-
integratedToolType: segment.data.integratedToolType,
|
|
51277
|
-
toolFunction: segment.data.toolFunction,
|
|
51278
|
-
toolTitle: segment.data.toolTitle,
|
|
51279
|
-
parameters: segment.data.parameters
|
|
51280
|
-
});
|
|
51281
|
-
hasIncompleteState = true;
|
|
51282
|
-
}
|
|
51283
|
-
break;
|
|
51284
|
-
case "approval_request":
|
|
51285
|
-
if (segment.status === "pending" && segment.data.requestId) {
|
|
51286
|
-
pendingApprovals.set(segment.data.requestId, {
|
|
51287
|
-
command: segment.data.command,
|
|
51288
|
-
explanation: segment.data.explanation,
|
|
51289
|
-
approvalType: segment.data.approvalType || "CLIENT"
|
|
51290
|
-
});
|
|
51291
|
-
hasIncompleteState = true;
|
|
51292
|
-
}
|
|
51293
|
-
break;
|
|
51294
|
-
case "approval_batch": {
|
|
51295
|
-
const allDone = !!segment.data.executions && segment.data.toolCalls.every(
|
|
51296
|
-
(c) => segment.data.executions?.[c.toolExecutionRequestId]?.status === "done"
|
|
51297
|
-
);
|
|
51298
|
-
if (segment.status !== "rejected" && !allDone) {
|
|
51299
|
-
hasIncompleteState = true;
|
|
51300
|
-
}
|
|
51301
|
-
break;
|
|
51302
|
-
}
|
|
51303
|
-
case "context_compaction":
|
|
51304
|
-
if (segment.status === "started") {
|
|
51305
|
-
hasIncompleteState = true;
|
|
51306
|
-
}
|
|
51307
|
-
break;
|
|
51308
|
-
}
|
|
51309
|
-
});
|
|
51310
|
-
if (!hasIncompleteState) {
|
|
51311
|
-
return void 0;
|
|
51312
|
-
}
|
|
51313
|
-
return {
|
|
51314
|
-
existingSegments: segments,
|
|
51315
|
-
pendingApprovals: pendingApprovals.size > 0 ? pendingApprovals : void 0,
|
|
51316
|
-
executingTools: executingTools.size > 0 ? executingTools : void 0
|
|
51317
|
-
};
|
|
51318
|
-
}
|
|
51319
|
-
|
|
51320
51733
|
// src/components/chat/utils/history-merge.ts
|
|
51321
51734
|
var SYNTHETIC_REALTIME_ID_PREFIXES = ["assistant-", "user-", "direct-", "system-", "error-"];
|
|
51322
51735
|
function isSyntheticRealtimeId(id) {
|
|
@@ -53701,11 +54114,14 @@ export {
|
|
|
53701
54114
|
processHistoricalMessages,
|
|
53702
54115
|
extractErrorMessages,
|
|
53703
54116
|
processHistoricalMessagesWithErrors,
|
|
54117
|
+
extractIncompleteMessageState,
|
|
54118
|
+
appendToTrailingAssistant,
|
|
54119
|
+
upsertTrailingCompaction,
|
|
54120
|
+
applyToolExecutionToMessages,
|
|
53704
54121
|
mapProcessedToUnified,
|
|
53705
54122
|
historicalToUnified,
|
|
53706
54123
|
useNatsChatAdapter,
|
|
53707
54124
|
useUnifiedChat,
|
|
53708
|
-
extractIncompleteMessageState,
|
|
53709
54125
|
SYNTHETIC_REALTIME_ID_PREFIXES,
|
|
53710
54126
|
flattenMessagePagesChronological,
|
|
53711
54127
|
maxPersistedStreamSeq,
|
|
@@ -54122,4 +54538,4 @@ export {
|
|
|
54122
54538
|
LogsList,
|
|
54123
54539
|
assets
|
|
54124
54540
|
};
|
|
54125
|
-
//# sourceMappingURL=chunk-
|
|
54541
|
+
//# sourceMappingURL=chunk-3BHV2QAH.js.map
|