@adminide-stack/yantra-mobile 12.0.53-alpha.1 → 12.0.53-alpha.12
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/lib/components/KeyboardComposerDock.js +55 -12
- package/lib/components/KeyboardComposerDock.js.map +1 -1
- package/lib/components/NavigationHeader/NavigationHeader.js +3 -1
- package/lib/components/NavigationHeader/NavigationHeader.js.map +1 -1
- package/lib/features/apps/AppsCatalog.js +1 -1
- package/lib/features/apps/AppsCatalog.js.map +1 -1
- package/lib/features/attachments/ComposerAttachMenu.js +189 -0
- package/lib/features/attachments/ComposerAttachMenu.js.map +1 -0
- package/lib/features/attachments/useImageAttachments.js +23 -15
- package/lib/features/attachments/useImageAttachments.js.map +1 -1
- package/lib/features/canvas/canvasBoardsSnapshot.js +45 -0
- package/lib/features/canvas/canvasBoardsSnapshot.js.map +1 -0
- package/lib/features/canvas/nativeViewerRegistry.js +9 -1
- package/lib/features/canvas/nativeViewerRegistry.js.map +1 -1
- package/lib/features/chat/ChatTranscript.js +7 -0
- package/lib/features/chat/ChatTranscript.js.map +1 -1
- package/lib/features/chat/chatHistorySnapshot.js +103 -0
- package/lib/features/chat/chatHistorySnapshot.js.map +1 -0
- package/lib/graphql/typePolicies.js +139 -0
- package/lib/graphql/typePolicies.js.map +1 -0
- package/lib/hooks/useCdecliChannel.js +63 -7
- package/lib/hooks/useCdecliChannel.js.map +1 -1
- package/lib/hooks/useChatApi.js +232 -26
- package/lib/hooks/useChatApi.js.map +1 -1
- package/lib/hooks/useChatStream.js +105 -36
- package/lib/hooks/useChatStream.js.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/module.js +5 -2
- package/lib/module.js.map +1 -1
- package/lib/screens/CanvasBoard/index.js +1 -1
- package/lib/screens/CanvasBoard/index.js.map +1 -1
- package/lib/screens/Chat/index.js +8 -38
- package/lib/screens/Chat/index.js.map +1 -1
- package/lib/screens/Home/HomeScreen.js +18 -31
- package/lib/screens/Home/HomeScreen.js.map +1 -1
- package/lib/screens/Home/components/CanvasPrewarm.js +3 -2
- package/lib/screens/Home/components/CanvasPrewarm.js.map +1 -1
- package/lib/screens/Home/components/ChatHistoryLanding.js +60 -12
- package/lib/screens/Home/components/ChatHistoryLanding.js.map +1 -1
- package/lib/state/chatThreadMerge.js +76 -2
- package/lib/state/chatThreadMerge.js.map +1 -1
- package/package.json +4 -4
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defProps = Object.defineProperties;
|
|
3
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __spreadValues = (a, b) => {
|
|
9
|
+
for (var prop in b || (b = {}))
|
|
10
|
+
if (__hasOwnProp.call(b, prop))
|
|
11
|
+
__defNormalProp(a, prop, b[prop]);
|
|
12
|
+
if (__getOwnPropSymbols)
|
|
13
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
14
|
+
if (__propIsEnum.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
}
|
|
17
|
+
return a;
|
|
18
|
+
};
|
|
19
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
function mergeConnectionEdges(existing, incoming, {
|
|
21
|
+
readField
|
|
22
|
+
}) {
|
|
23
|
+
var _a, _b;
|
|
24
|
+
if (!existing) return incoming;
|
|
25
|
+
const existingEdges = (_a = existing.edges) != null ? _a : [];
|
|
26
|
+
const incomingEdges = (_b = incoming.edges) != null ? _b : [];
|
|
27
|
+
const seenIds = /* @__PURE__ */ new Set();
|
|
28
|
+
const merged = [...incomingEdges];
|
|
29
|
+
incomingEdges.forEach((edge) => {
|
|
30
|
+
const node = readField("node", edge);
|
|
31
|
+
const id = node ? readField("id", node) : void 0;
|
|
32
|
+
if (id) seenIds.add(id);
|
|
33
|
+
});
|
|
34
|
+
existingEdges.forEach((edge) => {
|
|
35
|
+
const node = readField("node", edge);
|
|
36
|
+
const id = node ? readField("id", node) : void 0;
|
|
37
|
+
if (id && !seenIds.has(id)) {
|
|
38
|
+
merged.push(edge);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
return __spreadProps(__spreadValues({}, incoming), {
|
|
42
|
+
edges: merged
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function mergeNewsArticlesList(existing, incoming, {
|
|
46
|
+
args
|
|
47
|
+
}) {
|
|
48
|
+
var _a, _b, _c;
|
|
49
|
+
const skip = (_b = (_a = args == null ? void 0 : args.filter) == null ? void 0 : _a.skip) != null ? _b : 0;
|
|
50
|
+
const mergedData = (existing == null ? void 0 : existing.data) ? existing.data.slice(0) : [];
|
|
51
|
+
const incomingData = (_c = incoming == null ? void 0 : incoming.data) != null ? _c : [];
|
|
52
|
+
incomingData.forEach((item, index) => {
|
|
53
|
+
mergedData[skip + index] = item;
|
|
54
|
+
});
|
|
55
|
+
return __spreadProps(__spreadValues({}, incoming), {
|
|
56
|
+
data: mergedData
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
function mergeChannelsByUser(existing, incoming, {
|
|
60
|
+
args
|
|
61
|
+
}) {
|
|
62
|
+
var _a;
|
|
63
|
+
const skip = (_a = args == null ? void 0 : args.skip) != null ? _a : 0;
|
|
64
|
+
if (skip === 0) return incoming != null ? incoming : [];
|
|
65
|
+
const merged = existing ? existing.slice(0) : [];
|
|
66
|
+
(incoming != null ? incoming : []).forEach((channel, index) => {
|
|
67
|
+
merged[skip + index] = channel;
|
|
68
|
+
});
|
|
69
|
+
return merged;
|
|
70
|
+
}
|
|
71
|
+
function mergeMessagesConnection(existing, incoming, {
|
|
72
|
+
args
|
|
73
|
+
}) {
|
|
74
|
+
var _a, _b;
|
|
75
|
+
if (!incoming) return existing;
|
|
76
|
+
const skip = (_a = args == null ? void 0 : args.skip) != null ? _a : 0;
|
|
77
|
+
if (skip === 0 || !existing) return incoming;
|
|
78
|
+
const mergedData = (existing == null ? void 0 : existing.data) ? existing.data.slice(0) : [];
|
|
79
|
+
const incomingData = (_b = incoming == null ? void 0 : incoming.data) != null ? _b : [];
|
|
80
|
+
incomingData.forEach((item, index) => {
|
|
81
|
+
mergedData[skip + index] = item;
|
|
82
|
+
});
|
|
83
|
+
return __spreadProps(__spreadValues({}, incoming), {
|
|
84
|
+
data: mergedData
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
const typePolicies = {
|
|
88
|
+
Query: {
|
|
89
|
+
fields: {
|
|
90
|
+
// Chat sessions: ignore pagination args so cache stores one canonical list per archive filter
|
|
91
|
+
getAccountChatSessions: {
|
|
92
|
+
keyArgs: ["includeArchived"],
|
|
93
|
+
merge: mergeConnectionEdges
|
|
94
|
+
},
|
|
95
|
+
// Chat messages (account API): keyed by sessionId, ignore pagination args
|
|
96
|
+
getAccountChatMessages: {
|
|
97
|
+
keyArgs: ["sessionId"],
|
|
98
|
+
merge: mergeConnectionEdges
|
|
99
|
+
},
|
|
100
|
+
getAccountNewsArticles: {
|
|
101
|
+
keyArgs: ["filter", ["topic"]],
|
|
102
|
+
merge: mergeNewsArticlesList
|
|
103
|
+
},
|
|
104
|
+
// Chat-history channels: one canonical list per (role, criteria)
|
|
105
|
+
// — criteria carries { type, orgName }. Ignore limit/skip/sort so
|
|
106
|
+
// cache-first serves the same list across navigations and loadMore
|
|
107
|
+
// appends instead of replacing.
|
|
108
|
+
channelsByUser: {
|
|
109
|
+
keyArgs: ["role", "criteria"],
|
|
110
|
+
merge: mergeChannelsByUser
|
|
111
|
+
},
|
|
112
|
+
// History titles (`editedBy` + type) and thread details (`channelId`)
|
|
113
|
+
// must not share a cache slot. Drop skip/limit so pages merge.
|
|
114
|
+
messages: {
|
|
115
|
+
keyArgs: ["channelId", "editedBy", "type", "props", "sort", "parentId"],
|
|
116
|
+
merge: mergeMessagesConnection
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
// `MessengerUser` selects `fullName @client`. With no local resolver the cache
|
|
121
|
+
// cannot satisfy that field, so every UserAccount read is "incomplete" — which
|
|
122
|
+
// makes cache-first treat channelsByUser / messages as a miss and refetch on
|
|
123
|
+
// every navigation. Compute fullName locally so the cache reads back complete.
|
|
124
|
+
UserAccount: {
|
|
125
|
+
fields: {
|
|
126
|
+
fullName: {
|
|
127
|
+
read(_existing, {
|
|
128
|
+
readField
|
|
129
|
+
}) {
|
|
130
|
+
var _a, _b;
|
|
131
|
+
const given = (_a = readField("givenName")) != null ? _a : "";
|
|
132
|
+
const family = (_b = readField("familyName")) != null ? _b : "";
|
|
133
|
+
const joined = `${given} ${family}`.replace(/\s+/g, " ").trim();
|
|
134
|
+
return joined || readField("username") || "";
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
};export{typePolicies};//# sourceMappingURL=typePolicies.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typePolicies.js","sources":["../../src/graphql/typePolicies.ts"],"sourcesContent":["/**\n * Apollo cache field policies — same contract as account/browser.\n *\n * Without these, `cache-first` treats `channelsByUser` / `messages` as a miss\n * (pagination args re-key the list; `fullName @client` has no reader) and the\n * history screen + thread details refetch on every visit.\n */\n\nfunction mergeConnectionEdges(existing: any, incoming: any, { readField }: any) {\n if (!existing) return incoming;\n\n const existingEdges = existing.edges ?? [];\n const incomingEdges = incoming.edges ?? [];\n\n const seenIds = new Set<string>();\n const merged = [...incomingEdges];\n\n incomingEdges.forEach((edge: any) => {\n const node = readField('node', edge);\n const id = node ? readField('id', node) : undefined;\n if (id) seenIds.add(id as string);\n });\n\n existingEdges.forEach((edge: any) => {\n const node = readField('node', edge);\n const id = node ? readField('id', node) : undefined;\n if (id && !seenIds.has(id as string)) {\n merged.push(edge);\n }\n });\n\n return {\n ...incoming,\n edges: merged,\n };\n}\n\nfunction mergeNewsArticlesList(existing: any, incoming: any, { args }: any) {\n const skip = args?.filter?.skip ?? 0;\n const mergedData = existing?.data ? existing.data.slice(0) : [];\n const incomingData = incoming?.data ?? [];\n\n incomingData.forEach((item: any, index: number) => {\n mergedData[skip + index] = item;\n });\n\n return {\n ...incoming,\n data: mergedData,\n };\n}\n\n// Chat-history list: `channelsByUser` returns a flat list of normalized Channel\n// refs (each has an `id`). Append paginated pages by their `skip` offset into one\n// canonical list so loadMore (skip>0, network-only) extends the cache instead of\n// clobbering page 1. A fresh page-1 load (skip 0) replaces the list so pull-to-\n// refresh does not keep a stale tail. Pairs with `keyArgs` which drops\n// limit/skip/sort so all pages of the same (role, criteria) share one cache entry.\nfunction mergeChannelsByUser(existing: any[] | undefined, incoming: any[], { args }: any) {\n const skip = args?.skip ?? 0;\n if (skip === 0) return incoming ?? [];\n const merged = existing ? existing.slice(0) : [];\n (incoming ?? []).forEach((channel: any, index: number) => {\n merged[skip + index] = channel;\n });\n return merged;\n}\n\nfunction mergeMessagesConnection(existing: any, incoming: any, { args }: any) {\n if (!incoming) return existing;\n const skip = args?.skip ?? 0;\n if (skip === 0 || !existing) return incoming;\n\n const mergedData = existing?.data ? existing.data.slice(0) : [];\n const incomingData = incoming?.data ?? [];\n incomingData.forEach((item: any, index: number) => {\n mergedData[skip + index] = item;\n });\n return {\n ...incoming,\n data: mergedData,\n };\n}\n\nexport const typePolicies = {\n Query: {\n fields: {\n // Chat sessions: ignore pagination args so cache stores one canonical list per archive filter\n getAccountChatSessions: {\n keyArgs: ['includeArchived'],\n merge: mergeConnectionEdges,\n },\n // Chat messages (account API): keyed by sessionId, ignore pagination args\n getAccountChatMessages: {\n keyArgs: ['sessionId'],\n merge: mergeConnectionEdges,\n },\n getAccountNewsArticles: {\n keyArgs: ['filter', ['topic']],\n merge: mergeNewsArticlesList,\n },\n // Chat-history channels: one canonical list per (role, criteria)\n // — criteria carries { type, orgName }. Ignore limit/skip/sort so\n // cache-first serves the same list across navigations and loadMore\n // appends instead of replacing.\n channelsByUser: {\n keyArgs: ['role', 'criteria'],\n merge: mergeChannelsByUser,\n },\n // History titles (`editedBy` + type) and thread details (`channelId`)\n // must not share a cache slot. Drop skip/limit so pages merge.\n messages: {\n keyArgs: ['channelId', 'editedBy', 'type', 'props', 'sort', 'parentId'],\n merge: mergeMessagesConnection,\n },\n },\n },\n // `MessengerUser` selects `fullName @client`. With no local resolver the cache\n // cannot satisfy that field, so every UserAccount read is \"incomplete\" — which\n // makes cache-first treat channelsByUser / messages as a miss and refetch on\n // every navigation. Compute fullName locally so the cache reads back complete.\n UserAccount: {\n fields: {\n fullName: {\n read(_existing: string | undefined, { readField }: any): string {\n const given = (readField('givenName') as string | undefined) ?? '';\n const family = (readField('familyName') as string | undefined) ?? '';\n const joined = `${given} ${family}`.replace(/\\s+/g, ' ').trim();\n return joined || (readField('username') as string | undefined) || '';\n },\n },\n },\n },\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {useRef,useCallback,useEffect}from'react';import {AppState}from'react-native';import {quickReplyViaBrain}from'../services/brainQuickReply.js';import {useGatewaySendMessageMutation,useMessengerStreamDeltaSubscription,useGatewayInboundMessageByChannelSubscription}from'common/graphql';var __defProp = Object.defineProperty;
|
|
1
|
+
import {useRef,useCallback,useEffect}from'react';import {AppState}from'react-native';import {useApolloClient,gql}from'@apollo/client/index.js';import {quickReplyViaBrain}from'../services/brainQuickReply.js';import {useGatewaySendMessageMutation,useMessengerStreamDeltaSubscription,useGatewayInboundMessageByChannelSubscription}from'common/graphql';var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
3
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
4
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
@@ -14,6 +14,17 @@ var __spreadValues = (a, b) => {
|
|
|
14
14
|
}
|
|
15
15
|
return a;
|
|
16
16
|
};
|
|
17
|
+
const MESSENGER_ACTIVE_STREAM_QUERY = gql`
|
|
18
|
+
query MessengerActiveStreamResume($channelId: String!) {
|
|
19
|
+
messengerActiveStream(channelId: $channelId) {
|
|
20
|
+
runId
|
|
21
|
+
seq
|
|
22
|
+
channelId
|
|
23
|
+
text
|
|
24
|
+
isFinal
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
17
28
|
function stripModelCostHeader(content) {
|
|
18
29
|
const normalized = content.replace(/\r\n/g, "\n");
|
|
19
30
|
return normalized.replace(/^\s*(?:[^\w\n]+\s*)?[a-z0-9][a-z0-9._-]*\s*\(\s*\$[\d.]+\s*\/\s*MTok\s+in\s*\)\s*\n+/i, "");
|
|
@@ -31,6 +42,15 @@ function useCdecliChannel(isConnected, accountId, channelId, callbacks, model, s
|
|
|
31
42
|
const reconnectedStreamRef = useRef(false);
|
|
32
43
|
const streamCompletedRef = useRef(false);
|
|
33
44
|
const accumulatedLenRef = useRef(0);
|
|
45
|
+
const lastRunIdRef = useRef(null);
|
|
46
|
+
const apolloClient = useApolloClient();
|
|
47
|
+
const seededChannelRef = useRef(null);
|
|
48
|
+
const ingestAccumulatedText = useCallback((accumulated) => {
|
|
49
|
+
const fullText = stripModelCostHeader(accumulated);
|
|
50
|
+
const newChunk = fullText.substring(accumulatedLenRef.current);
|
|
51
|
+
accumulatedLenRef.current = fullText.length;
|
|
52
|
+
if (newChunk) cbRef.current.onChunk(newChunk);
|
|
53
|
+
}, []);
|
|
34
54
|
const quickReplyShownRef = useRef(false);
|
|
35
55
|
const turnSeqRef = useRef(0);
|
|
36
56
|
const timeoutRef = useRef(null);
|
|
@@ -74,6 +94,10 @@ function useCdecliChannel(isConnected, accountId, channelId, callbacks, model, s
|
|
|
74
94
|
const delta = (_a = data == null ? void 0 : data.data) == null ? void 0 : _a.messengerStreamDelta;
|
|
75
95
|
if (!delta) return;
|
|
76
96
|
if (delta.isFinal) return;
|
|
97
|
+
if (delta.runId && delta.runId !== lastRunIdRef.current) {
|
|
98
|
+
accumulatedLenRef.current = 0;
|
|
99
|
+
}
|
|
100
|
+
if (delta.runId) lastRunIdRef.current = delta.runId;
|
|
77
101
|
if (streamCompletedRef.current) return;
|
|
78
102
|
if (!pendingRef.current) {
|
|
79
103
|
if (!reconnectedStreamRef.current) {
|
|
@@ -87,17 +111,46 @@ function useCdecliChannel(isConnected, accountId, channelId, callbacks, model, s
|
|
|
87
111
|
}
|
|
88
112
|
hasReceivedDeltasRef.current = true;
|
|
89
113
|
armTimeout();
|
|
90
|
-
|
|
91
|
-
const newChunk = fullText.substring(accumulatedLenRef.current);
|
|
92
|
-
accumulatedLenRef.current = fullText.length;
|
|
93
|
-
if (newChunk) {
|
|
94
|
-
cbRef.current.onChunk(newChunk);
|
|
95
|
-
}
|
|
114
|
+
ingestAccumulatedText((_d = delta.text) != null ? _d : "");
|
|
96
115
|
},
|
|
97
116
|
onError: (err) => {
|
|
98
117
|
console.error("[useCdecliChannel] stream delta subscription error:", err);
|
|
99
118
|
}
|
|
100
119
|
});
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (streamSkip || !streamChannelId) return void 0;
|
|
122
|
+
if (seededChannelRef.current === streamChannelId) return void 0;
|
|
123
|
+
seededChannelRef.current = streamChannelId;
|
|
124
|
+
accumulatedLenRef.current = 0;
|
|
125
|
+
streamCompletedRef.current = false;
|
|
126
|
+
reconnectedStreamRef.current = false;
|
|
127
|
+
lastRunIdRef.current = null;
|
|
128
|
+
let cancelled = false;
|
|
129
|
+
apolloClient.query({
|
|
130
|
+
query: MESSENGER_ACTIVE_STREAM_QUERY,
|
|
131
|
+
variables: {
|
|
132
|
+
channelId: streamChannelId
|
|
133
|
+
},
|
|
134
|
+
fetchPolicy: "network-only",
|
|
135
|
+
errorPolicy: "all"
|
|
136
|
+
}).then(({
|
|
137
|
+
data
|
|
138
|
+
}) => {
|
|
139
|
+
if (cancelled) return;
|
|
140
|
+
const snapshot = data == null ? void 0 : data.messengerActiveStream;
|
|
141
|
+
if (!(snapshot == null ? void 0 : snapshot.text) || snapshot.isFinal) return;
|
|
142
|
+
if (streamCompletedRef.current) return;
|
|
143
|
+
if (accumulatedLenRef.current > 0) return;
|
|
144
|
+
reconnectedStreamRef.current = true;
|
|
145
|
+
hasReceivedDeltasRef.current = true;
|
|
146
|
+
if (snapshot.runId) lastRunIdRef.current = snapshot.runId;
|
|
147
|
+
ingestAccumulatedText(snapshot.text);
|
|
148
|
+
}).catch(() => {
|
|
149
|
+
});
|
|
150
|
+
return () => {
|
|
151
|
+
cancelled = true;
|
|
152
|
+
};
|
|
153
|
+
}, [streamChannelId, streamSkip, apolloClient, ingestAccumulatedText]);
|
|
101
154
|
useGatewayInboundMessageByChannelSubscription({
|
|
102
155
|
variables: {
|
|
103
156
|
channelId: streamChannelId
|
|
@@ -123,6 +176,7 @@ function useCdecliChannel(isConnected, accountId, channelId, callbacks, model, s
|
|
|
123
176
|
reconnectedStreamRef.current = false;
|
|
124
177
|
streamCompletedRef.current = true;
|
|
125
178
|
accumulatedLenRef.current = 0;
|
|
179
|
+
lastRunIdRef.current = null;
|
|
126
180
|
if (timeoutRef.current) {
|
|
127
181
|
clearTimeout(timeoutRef.current);
|
|
128
182
|
timeoutRef.current = null;
|
|
@@ -144,6 +198,7 @@ function useCdecliChannel(isConnected, accountId, channelId, callbacks, model, s
|
|
|
144
198
|
reconnectedStreamRef.current = false;
|
|
145
199
|
streamCompletedRef.current = false;
|
|
146
200
|
accumulatedLenRef.current = 0;
|
|
201
|
+
lastRunIdRef.current = null;
|
|
147
202
|
quickReplyShownRef.current = false;
|
|
148
203
|
const turn = ++turnSeqRef.current;
|
|
149
204
|
void quickReplyViaBrain(text).then((answer) => {
|
|
@@ -195,6 +250,7 @@ function useCdecliChannel(isConnected, accountId, channelId, callbacks, model, s
|
|
|
195
250
|
reconnectedStreamRef.current = false;
|
|
196
251
|
streamCompletedRef.current = false;
|
|
197
252
|
accumulatedLenRef.current = 0;
|
|
253
|
+
lastRunIdRef.current = null;
|
|
198
254
|
if (timeoutRef.current) {
|
|
199
255
|
clearTimeout(timeoutRef.current);
|
|
200
256
|
timeoutRef.current = null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCdecliChannel.js","sources":["../../src/hooks/useCdecliChannel.ts"],"sourcesContent":["/**\n * useCdecliChannel — wires the cdecli-serve messenger-gateway channel into the mobile chat UI.\n *\n * Kept in sync with `packages-modules/account/browser/src/hooks/useCdecliChannel.ts`.\n * When the CDeCLI channel is connected:\n * - `sendMessage(text, chatId, media)` calls `gatewaySendMessage`\n * - `MessengerStreamDelta` subscription delivers streaming chunks via `onChunk`\n * - `GatewayInboundMessageByChannel` delivers the final reply via `onComplete`\n */\n\nimport { useCallback, useEffect, useRef } from 'react';\nimport { AppState } from 'react-native';\nimport { quickReplyViaBrain } from '../services/brainQuickReply';\nimport {\n useGatewaySendMessageMutation,\n useGatewayInboundMessageByChannelSubscription,\n useMessengerStreamDeltaSubscription,\n} from 'common/graphql';\n\nfunction stripModelCostHeader(content: string): string {\n const normalized = content.replace(/\\r\\n/g, '\\n');\n return normalized.replace(\n /^\\s*(?:[^\\w\\n]+\\s*)?[a-z0-9][a-z0-9._-]*\\s*\\(\\s*\\$[\\d.]+\\s*\\/\\s*MTok\\s+in\\s*\\)\\s*\\n+/i,\n '',\n );\n}\n\n// `error?: undefined` on the success arm keeps `result.error` reachable on the\n// union: with strictNullChecks off (repo-wide), TS will not narrow the\n// discriminated union after an `if (result.ok) continue`.\nexport type SteerResult = { ok: true; error?: undefined } | { ok: false; error: string };\n\nexport interface CdecliChannelCallbacks {\n onChunk: (text: string) => void;\n /**\n * A fast provisional answer from `yantra-brain`, painted while the real agent\n * is still bootstrapping. Distinct from onChunk on purpose: the UI shows it as\n * the reply-so-far and REPLACES it the moment real deltas arrive, so the brain\n * fills the silence without ever stacking on top of the agent's answer.\n */\n onQuickReply?: (text: string) => void;\n onComplete: (text: string) => void;\n onError: (error: string) => void;\n}\n\nexport function isNoActiveSessionError(message: string): boolean {\n return /no active session/i.test(message);\n}\n\n/**\n * Idle window, not a total budget. The timer is re-armed on every streamed\n * delta (a turn that is actively streaming is not stuck), and paused while the\n * app is backgrounded (iOS suspends the WebSocket + throttles JS timers, so a\n * wall-clock timer would otherwise fire a false \"did not respond\" the instant\n * the app returns to the foreground). It fires only after this much CONTINUOUS\n * silence with the app in the foreground.\n */\nconst CDECLI_RESPONSE_TIMEOUT_MS = 300_000;\n\nexport function useCdecliChannel(\n isConnected: boolean,\n accountId: string,\n channelId: string | undefined,\n callbacks: CdecliChannelCallbacks,\n model?: string,\n skill?: string,\n) {\n const [sendMutation] = useGatewaySendMessageMutation();\n const cbRef = useRef(callbacks);\n cbRef.current = callbacks;\n\n const pendingRef = useRef<{ text: string; sentAt: number } | null>(null);\n const hasReceivedDeltasRef = useRef(false);\n const reconnectedStreamRef = useRef(false);\n const streamCompletedRef = useRef(false);\n const accumulatedLenRef = useRef(0);\n // True while a brain quick-reply is what the user is looking at. The first\n // real delta clears the provisional text before painting, so the agent's\n // answer replaces the brain's rather than appending to it.\n const quickReplyShownRef = useRef(false);\n // Identity of the current turn for the brain race. A counter, not a\n // timestamp: two sends can share a millisecond, and a timestamp would then\n // let a brain answer for a superseded turn paint over the live one.\n const turnSeqRef = useRef(0);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const streamSkip = !channelId;\n const streamChannelId = channelId || accountId;\n\n /** (Re)start the idle timer for the in-flight turn. No-op if none pending. */\n const armTimeout = useCallback(() => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n if (!pendingRef.current) {\n timeoutRef.current = null;\n return;\n }\n timeoutRef.current = setTimeout(() => {\n if (pendingRef.current) {\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n timeoutRef.current = null;\n cbRef.current.onError(\n 'CDeCLI agent did not respond within 300 seconds. The query may still be processing.',\n );\n }\n }, CDECLI_RESPONSE_TIMEOUT_MS);\n }, []);\n\n // Pause the idle timer in the background, re-arm fresh on return. iOS\n // suspends the streaming WebSocket and throttles JS timers while\n // backgrounded, so a running wall-clock timer either fires against a\n // connection that cannot deliver or fires the instant the app resumes -\n // both read to the user as a spurious timeout. On resume the subscription\n // reconnects and redelivers the final message if the turn finished while\n // away; if it is still pending, the fresh window starts counting from the\n // foreground.\n useEffect(() => {\n const sub = AppState.addEventListener('change', (next) => {\n if (next === 'active') {\n if (pendingRef.current && !streamCompletedRef.current) armTimeout();\n } else if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n });\n return () => sub.remove();\n }, [armTimeout]);\n\n useMessengerStreamDeltaSubscription({\n variables: { channelId: streamChannelId },\n skip: streamSkip,\n onData: ({ data }) => {\n const delta = data?.data?.messengerStreamDelta;\n if (!delta) return;\n\n if (delta.isFinal) return;\n\n if (streamCompletedRef.current) return;\n\n if (!pendingRef.current) {\n if (!reconnectedStreamRef.current) {\n reconnectedStreamRef.current = true;\n accumulatedLenRef.current = 0;\n }\n }\n\n if (quickReplyShownRef.current) {\n // The real answer has started: clear the brain's provisional reply\n // before the first chunk lands, so it is replaced, not appended to.\n quickReplyShownRef.current = false;\n cbRef.current.onQuickReply?.('');\n }\n hasReceivedDeltasRef.current = true;\n\n // Heartbeat: a turn that is actively streaming is not stuck, so\n // push the idle deadline out on every delta. The timer now fires\n // only after real silence, never mid-stream on a long query.\n armTimeout();\n\n const fullText = stripModelCostHeader(delta.text ?? '');\n const newChunk = fullText.substring(accumulatedLenRef.current);\n accumulatedLenRef.current = fullText.length;\n\n if (newChunk) {\n cbRef.current.onChunk(newChunk);\n }\n },\n onError: (err) => {\n console.error('[useCdecliChannel] stream delta subscription error:', err);\n },\n });\n\n useGatewayInboundMessageByChannelSubscription({\n variables: { channelId: streamChannelId },\n skip: !isConnected || streamSkip,\n onData: ({ data }) => {\n const msg = data?.data?.gatewayInboundMessageByChannel;\n if (!msg?.text) return;\n const sanitizedText = stripModelCostHeader(msg.text);\n\n if (!hasReceivedDeltasRef.current) {\n if (quickReplyShownRef.current) {\n quickReplyShownRef.current = false;\n cbRef.current.onQuickReply?.('');\n }\n cbRef.current.onChunk(sanitizedText);\n }\n\n cbRef.current.onComplete(sanitizedText);\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = true;\n accumulatedLenRef.current = 0;\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n },\n onError: (err) => {\n console.error('[useCdecliChannel] subscription error:', err);\n cbRef.current.onError(err.message || 'CDeCLI subscription error');\n },\n });\n\n const sendMessage = useCallback(\n async (\n text: string,\n chatId = 'messenger',\n media: Array<{ type: string; url: string; data?: string; mimeType?: string; filename?: string }> = [],\n ): Promise<boolean> => {\n if (!isConnected) return false;\n\n pendingRef.current = { text, sentAt: Date.now() };\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = false;\n accumulatedLenRef.current = 0;\n quickReplyShownRef.current = false;\n\n // Ask the brain the same question in parallel with the send. On a cold\n // first turn the agent can take minutes before its first delta; the\n // brain answers in seconds. Its reply is painted only if nothing real\n // has arrived yet, and is replaced in place the moment it does. Fire\n // and forget: a brain failure changes nothing about the turn.\n const turn = ++turnSeqRef.current;\n void quickReplyViaBrain(text).then((answer) => {\n if (!answer) return;\n // Stale if the turn moved on, or the agent already spoke.\n if (turnSeqRef.current !== turn || !pendingRef.current) return;\n if (hasReceivedDeltasRef.current || streamCompletedRef.current) return;\n quickReplyShownRef.current = true;\n cbRef.current.onQuickReply?.(answer);\n });\n\n try {\n const result = await sendMutation({\n variables: {\n input: {\n channelType: 'cdecli-serve',\n accountId,\n chatId,\n text,\n ...(media.length > 0 ? { media: media as never } : {}),\n ...(model || skill\n ? { metadata: { ...(model && { model }), ...(skill && { skill }) } }\n : {}),\n },\n },\n });\n\n const payload = result.data?.gatewaySendMessage;\n if (!payload?.success) {\n const errMsg = payload?.error || 'CDeCLI send failed';\n cbRef.current.onError(errMsg);\n pendingRef.current = null;\n return false;\n }\n\n armTimeout();\n\n return true;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n cbRef.current.onError(msg);\n pendingRef.current = null;\n return false;\n }\n },\n [isConnected, accountId, channelId, sendMutation, model, skill, armTimeout],\n );\n\n useEffect(\n () => () => {\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = false;\n accumulatedLenRef.current = 0;\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n },\n [],\n );\n\n /**\n * Inject a follow-up into the turn that is currently streaming.\n * Same `gatewaySendMessage` mutation with `metadata.steer = true` (browser\n * `useCdecliChannel.steer`). Do NOT reset streaming refs: the existing\n * delta subscription must keep running.\n *\n * \"Cannot steer: no active session\" is an expected race before cdecli has\n * started the turn. Callers should queue and retry; do not `console.error`\n * (that pops the RN LogBox and looks like a crash).\n */\n const steer = useCallback(\n async (text: string, chatId = 'messenger'): Promise<SteerResult> => {\n if (!isConnected) return { ok: false, error: 'CDeCLI is not connected.' };\n try {\n const result = await sendMutation({\n variables: {\n input: {\n channelType: 'cdecli-serve',\n accountId,\n chatId,\n text,\n metadata: { steer: true },\n },\n },\n });\n const payload = result.data?.gatewaySendMessage;\n if (!payload?.success) {\n const errMsg = payload?.error || 'CDeCLI steer failed';\n if (!isNoActiveSessionError(errMsg)) {\n console.warn('[useCdecliChannel] steer failed:', errMsg);\n }\n return { ok: false, error: errMsg };\n }\n return { ok: true };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn('[useCdecliChannel] steer mutation error:', msg);\n return { ok: false, error: msg };\n }\n },\n [isConnected, accountId, sendMutation],\n );\n\n /**\n * Abort the in-flight turn. `metadata.cancel = true` maps to\n * `POST /v1/chat/cancel` on cdecli-serve (browser parity).\n */\n const cancel = useCallback(\n async (chatId = 'messenger'): Promise<boolean> => {\n if (!isConnected) return false;\n pendingRef.current = null;\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n try {\n const result = await sendMutation({\n variables: {\n input: {\n channelType: 'cdecli-serve',\n accountId,\n chatId,\n text: '',\n metadata: { cancel: true },\n },\n },\n });\n const payload = result.data?.gatewaySendMessage;\n if (!payload?.success) {\n console.error('[useCdecliChannel] cancel failed:', payload?.error || 'CDeCLI cancel failed');\n return false;\n }\n return true;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error('[useCdecliChannel] cancel mutation error:', msg);\n return false;\n }\n },\n [isConnected, accountId, sendMutation],\n );\n\n return { sendMessage, steer, cancel };\n}\n"],"names":["_a"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useCdecliChannel.js","sources":["../../src/hooks/useCdecliChannel.ts"],"sourcesContent":["/**\n * useCdecliChannel — wires the cdecli-serve messenger-gateway channel into the mobile chat UI.\n *\n * Kept in sync with `packages-modules/account/browser/src/hooks/useCdecliChannel.ts`.\n * When the CDeCLI channel is connected:\n * - `sendMessage(text, chatId, media)` calls `gatewaySendMessage`\n * - `MessengerStreamDelta` subscription delivers streaming chunks via `onChunk`\n * - `GatewayInboundMessageByChannel` delivers the final reply via `onComplete`\n */\n\nimport { useCallback, useEffect, useRef } from 'react';\nimport { AppState } from 'react-native';\nimport { gql, useApolloClient } from '@apollo/client';\nimport { quickReplyViaBrain } from '../services/brainQuickReply';\nimport {\n useGatewaySendMessageMutation,\n useGatewayInboundMessageByChannelSubscription,\n useMessengerStreamDeltaSubscription,\n} from 'common/graphql';\n\n/**\n * Resume snapshot for a channel's ACTIVE stream (server-owned).\n * Same document as browser `useCdecliChannel` — older backends error and we skip.\n */\nconst MESSENGER_ACTIVE_STREAM_QUERY = gql`\n query MessengerActiveStreamResume($channelId: String!) {\n messengerActiveStream(channelId: $channelId) {\n runId\n seq\n channelId\n text\n isFinal\n }\n }\n`;\n\nfunction stripModelCostHeader(content: string): string {\n const normalized = content.replace(/\\r\\n/g, '\\n');\n return normalized.replace(\n /^\\s*(?:[^\\w\\n]+\\s*)?[a-z0-9][a-z0-9._-]*\\s*\\(\\s*\\$[\\d.]+\\s*\\/\\s*MTok\\s+in\\s*\\)\\s*\\n+/i,\n '',\n );\n}\n\n// `error?: undefined` on the success arm keeps `result.error` reachable on the\n// union: with strictNullChecks off (repo-wide), TS will not narrow the\n// discriminated union after an `if (result.ok) continue`.\nexport type SteerResult = { ok: true; error?: undefined } | { ok: false; error: string };\n\nexport interface CdecliChannelCallbacks {\n onChunk: (text: string) => void;\n /**\n * A fast provisional answer from `yantra-brain`, painted while the real agent\n * is still bootstrapping. Distinct from onChunk on purpose: the UI shows it as\n * the reply-so-far and REPLACES it the moment real deltas arrive, so the brain\n * fills the silence without ever stacking on top of the agent's answer.\n */\n onQuickReply?: (text: string) => void;\n onComplete: (text: string) => void;\n onError: (error: string) => void;\n}\n\nexport function isNoActiveSessionError(message: string): boolean {\n return /no active session/i.test(message);\n}\n\n/**\n * Idle window, not a total budget. The timer is re-armed on every streamed\n * delta (a turn that is actively streaming is not stuck), and paused while the\n * app is backgrounded (iOS suspends the WebSocket + throttles JS timers, so a\n * wall-clock timer would otherwise fire a false \"did not respond\" the instant\n * the app returns to the foreground). It fires only after this much CONTINUOUS\n * silence with the app in the foreground.\n */\nconst CDECLI_RESPONSE_TIMEOUT_MS = 300_000;\n\nexport function useCdecliChannel(\n isConnected: boolean,\n accountId: string,\n channelId: string | undefined,\n callbacks: CdecliChannelCallbacks,\n model?: string,\n skill?: string,\n) {\n const [sendMutation] = useGatewaySendMessageMutation();\n const cbRef = useRef(callbacks);\n cbRef.current = callbacks;\n\n const pendingRef = useRef<{ text: string; sentAt: number } | null>(null);\n const hasReceivedDeltasRef = useRef(false);\n const reconnectedStreamRef = useRef(false);\n const streamCompletedRef = useRef(false);\n const accumulatedLenRef = useRef(0);\n const lastRunIdRef = useRef<string | null>(null);\n const apolloClient = useApolloClient();\n const seededChannelRef = useRef<string | null>(null);\n\n /**\n * Forward newly-accumulated stream text. Shared by live deltas and the\n * mount-time resume seed so neither gaps nor double-delivery happen when\n * the user leaves Chat for history and comes back mid-turn.\n */\n const ingestAccumulatedText = useCallback((accumulated: string) => {\n const fullText = stripModelCostHeader(accumulated);\n const newChunk = fullText.substring(accumulatedLenRef.current);\n accumulatedLenRef.current = fullText.length;\n if (newChunk) cbRef.current.onChunk(newChunk);\n }, []);\n // True while a brain quick-reply is what the user is looking at. The first\n // real delta clears the provisional text before painting, so the agent's\n // answer replaces the brain's rather than appending to it.\n const quickReplyShownRef = useRef(false);\n // Identity of the current turn for the brain race. A counter, not a\n // timestamp: two sends can share a millisecond, and a timestamp would then\n // let a brain answer for a superseded turn paint over the live one.\n const turnSeqRef = useRef(0);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const streamSkip = !channelId;\n const streamChannelId = channelId || accountId;\n\n /** (Re)start the idle timer for the in-flight turn. No-op if none pending. */\n const armTimeout = useCallback(() => {\n if (timeoutRef.current) clearTimeout(timeoutRef.current);\n if (!pendingRef.current) {\n timeoutRef.current = null;\n return;\n }\n timeoutRef.current = setTimeout(() => {\n if (pendingRef.current) {\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n timeoutRef.current = null;\n cbRef.current.onError(\n 'CDeCLI agent did not respond within 300 seconds. The query may still be processing.',\n );\n }\n }, CDECLI_RESPONSE_TIMEOUT_MS);\n }, []);\n\n // Pause the idle timer in the background, re-arm fresh on return. iOS\n // suspends the streaming WebSocket and throttles JS timers while\n // backgrounded, so a running wall-clock timer either fires against a\n // connection that cannot deliver or fires the instant the app resumes -\n // both read to the user as a spurious timeout. On resume the subscription\n // reconnects and redelivers the final message if the turn finished while\n // away; if it is still pending, the fresh window starts counting from the\n // foreground.\n useEffect(() => {\n const sub = AppState.addEventListener('change', (next) => {\n if (next === 'active') {\n if (pendingRef.current && !streamCompletedRef.current) armTimeout();\n } else if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n });\n return () => sub.remove();\n }, [armTimeout]);\n\n useMessengerStreamDeltaSubscription({\n variables: { channelId: streamChannelId },\n skip: streamSkip,\n onData: ({ data }) => {\n const delta = data?.data?.messengerStreamDelta;\n if (!delta) return;\n\n if (delta.isFinal) return;\n\n if (delta.runId && delta.runId !== lastRunIdRef.current) {\n accumulatedLenRef.current = 0;\n }\n if (delta.runId) lastRunIdRef.current = delta.runId;\n\n if (streamCompletedRef.current) return;\n\n // Pick up a turn that kept running after the user left Chat for history.\n if (!pendingRef.current) {\n if (!reconnectedStreamRef.current) {\n reconnectedStreamRef.current = true;\n accumulatedLenRef.current = 0;\n }\n }\n\n if (quickReplyShownRef.current) {\n // The real answer has started: clear the brain's provisional reply\n // before the first chunk lands, so it is replaced, not appended to.\n quickReplyShownRef.current = false;\n cbRef.current.onQuickReply?.('');\n }\n hasReceivedDeltasRef.current = true;\n\n // Heartbeat: a turn that is actively streaming is not stuck, so\n // push the idle deadline out on every delta. The timer now fires\n // only after real silence, never mid-stream on a long query.\n armTimeout();\n\n ingestAccumulatedText(delta.text ?? '');\n },\n onError: (err) => {\n console.error('[useCdecliChannel] stream delta subscription error:', err);\n },\n });\n\n // Seed the in-flight reply when Chat remounts (history → chat) mid-stream.\n useEffect(() => {\n if (streamSkip || !streamChannelId) return undefined;\n if (seededChannelRef.current === streamChannelId) return undefined;\n seededChannelRef.current = streamChannelId;\n accumulatedLenRef.current = 0;\n streamCompletedRef.current = false;\n reconnectedStreamRef.current = false;\n lastRunIdRef.current = null;\n\n let cancelled = false;\n apolloClient\n .query({\n query: MESSENGER_ACTIVE_STREAM_QUERY,\n variables: { channelId: streamChannelId },\n fetchPolicy: 'network-only',\n errorPolicy: 'all',\n })\n .then(({ data }) => {\n if (cancelled) return;\n const snapshot = data?.messengerActiveStream as\n | { runId?: string; text?: string; isFinal?: boolean }\n | null\n | undefined;\n if (!snapshot?.text || snapshot.isFinal) return;\n if (streamCompletedRef.current) return;\n if (accumulatedLenRef.current > 0) return;\n reconnectedStreamRef.current = true;\n hasReceivedDeltasRef.current = true;\n if (snapshot.runId) lastRunIdRef.current = snapshot.runId;\n ingestAccumulatedText(snapshot.text);\n })\n .catch(() => {\n /* pre-#701 backend or transient failure — live deltas self-heal */\n });\n return () => {\n cancelled = true;\n };\n }, [streamChannelId, streamSkip, apolloClient, ingestAccumulatedText]);\n\n useGatewayInboundMessageByChannelSubscription({\n variables: { channelId: streamChannelId },\n skip: !isConnected || streamSkip,\n onData: ({ data }) => {\n const msg = data?.data?.gatewayInboundMessageByChannel;\n if (!msg?.text) return;\n const sanitizedText = stripModelCostHeader(msg.text);\n\n if (!hasReceivedDeltasRef.current) {\n if (quickReplyShownRef.current) {\n quickReplyShownRef.current = false;\n cbRef.current.onQuickReply?.('');\n }\n cbRef.current.onChunk(sanitizedText);\n }\n\n cbRef.current.onComplete(sanitizedText);\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = true;\n accumulatedLenRef.current = 0;\n lastRunIdRef.current = null;\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n },\n onError: (err) => {\n console.error('[useCdecliChannel] subscription error:', err);\n cbRef.current.onError(err.message || 'CDeCLI subscription error');\n },\n });\n\n const sendMessage = useCallback(\n async (\n text: string,\n chatId = 'messenger',\n media: Array<{ type: string; url: string; data?: string; mimeType?: string; filename?: string }> = [],\n ): Promise<boolean> => {\n if (!isConnected) return false;\n\n pendingRef.current = { text, sentAt: Date.now() };\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = false;\n accumulatedLenRef.current = 0;\n lastRunIdRef.current = null;\n quickReplyShownRef.current = false;\n\n // Ask the brain the same question in parallel with the send. On a cold\n // first turn the agent can take minutes before its first delta; the\n // brain answers in seconds. Its reply is painted only if nothing real\n // has arrived yet, and is replaced in place the moment it does. Fire\n // and forget: a brain failure changes nothing about the turn.\n const turn = ++turnSeqRef.current;\n void quickReplyViaBrain(text).then((answer) => {\n if (!answer) return;\n // Stale if the turn moved on, or the agent already spoke.\n if (turnSeqRef.current !== turn || !pendingRef.current) return;\n if (hasReceivedDeltasRef.current || streamCompletedRef.current) return;\n quickReplyShownRef.current = true;\n cbRef.current.onQuickReply?.(answer);\n });\n\n try {\n const result = await sendMutation({\n variables: {\n input: {\n channelType: 'cdecli-serve',\n accountId,\n chatId,\n text,\n ...(media.length > 0 ? { media: media as never } : {}),\n ...(model || skill\n ? { metadata: { ...(model && { model }), ...(skill && { skill }) } }\n : {}),\n },\n },\n });\n\n const payload = result.data?.gatewaySendMessage;\n if (!payload?.success) {\n const errMsg = payload?.error || 'CDeCLI send failed';\n cbRef.current.onError(errMsg);\n pendingRef.current = null;\n return false;\n }\n\n armTimeout();\n\n return true;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n cbRef.current.onError(msg);\n pendingRef.current = null;\n return false;\n }\n },\n [isConnected, accountId, channelId, sendMutation, model, skill, armTimeout],\n );\n\n useEffect(\n () => () => {\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = false;\n accumulatedLenRef.current = 0;\n lastRunIdRef.current = null;\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n },\n [],\n );\n\n /**\n * Inject a follow-up into the turn that is currently streaming.\n * Same `gatewaySendMessage` mutation with `metadata.steer = true` (browser\n * `useCdecliChannel.steer`). Do NOT reset streaming refs: the existing\n * delta subscription must keep running.\n *\n * \"Cannot steer: no active session\" is an expected race before cdecli has\n * started the turn. Callers should queue and retry; do not `console.error`\n * (that pops the RN LogBox and looks like a crash).\n */\n const steer = useCallback(\n async (text: string, chatId = 'messenger'): Promise<SteerResult> => {\n if (!isConnected) return { ok: false, error: 'CDeCLI is not connected.' };\n try {\n const result = await sendMutation({\n variables: {\n input: {\n channelType: 'cdecli-serve',\n accountId,\n chatId,\n text,\n metadata: { steer: true },\n },\n },\n });\n const payload = result.data?.gatewaySendMessage;\n if (!payload?.success) {\n const errMsg = payload?.error || 'CDeCLI steer failed';\n if (!isNoActiveSessionError(errMsg)) {\n console.warn('[useCdecliChannel] steer failed:', errMsg);\n }\n return { ok: false, error: errMsg };\n }\n return { ok: true };\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.warn('[useCdecliChannel] steer mutation error:', msg);\n return { ok: false, error: msg };\n }\n },\n [isConnected, accountId, sendMutation],\n );\n\n /**\n * Abort the in-flight turn. `metadata.cancel = true` maps to\n * `POST /v1/chat/cancel` on cdecli-serve (browser parity).\n */\n const cancel = useCallback(\n async (chatId = 'messenger'): Promise<boolean> => {\n if (!isConnected) return false;\n pendingRef.current = null;\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n try {\n const result = await sendMutation({\n variables: {\n input: {\n channelType: 'cdecli-serve',\n accountId,\n chatId,\n text: '',\n metadata: { cancel: true },\n },\n },\n });\n const payload = result.data?.gatewaySendMessage;\n if (!payload?.success) {\n console.error('[useCdecliChannel] cancel failed:', payload?.error || 'CDeCLI cancel failed');\n return false;\n }\n return true;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error('[useCdecliChannel] cancel mutation error:', msg);\n return false;\n }\n },\n [isConnected, accountId, sendMutation],\n );\n\n return { sendMessage, steer, cancel };\n}\n"],"names":["_a"],"mappings":"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"}
|