@adminide-stack/yantra-mobile 12.0.28-alpha.67 → 12.0.28-alpha.69
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/api/stt.js +54 -0
- package/lib/api/stt.js.map +1 -0
- package/lib/components/GatewayConnector/GatewayConnector.js +18 -0
- package/lib/components/GatewayConnector/GatewayConnector.js.map +1 -0
- package/lib/components/NavigationHeader/NavigationHeader.js +214 -0
- package/lib/components/NavigationHeader/NavigationHeader.js.map +1 -0
- package/lib/components/ThinkingIndicator.js +55 -0
- package/lib/components/ThinkingIndicator.js.map +1 -0
- package/lib/compute.js +108 -31
- package/lib/compute.js.map +1 -1
- package/lib/contexts/CdecliConnectionContext.js +47 -0
- package/lib/contexts/CdecliConnectionContext.js.map +1 -0
- package/lib/contexts/GatewayContext.js +1 -1
- package/lib/features/audio-input/AudioRecorderPanel.js +231 -0
- package/lib/features/audio-input/AudioRecorderPanel.js.map +1 -0
- package/lib/features/audio-input/MicErrorBoundary.js +34 -0
- package/lib/features/audio-input/MicErrorBoundary.js.map +1 -0
- package/lib/hooks/useCdecliAutoConnect.js +41 -18
- package/lib/hooks/useCdecliAutoConnect.js.map +1 -1
- package/lib/hooks/useChatApi.js +158 -41
- package/lib/hooks/useChatApi.js.map +1 -1
- package/lib/hooks/useChatStream.js +59 -16
- package/lib/hooks/useChatStream.js.map +1 -1
- package/lib/hooks/usePrerequisiteIds.js +8 -12
- package/lib/hooks/usePrerequisiteIds.js.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/routes.json +112 -0
- package/lib/screens/Chat/index.js +423 -0
- package/lib/screens/Chat/index.js.map +1 -0
- package/lib/screens/ChatHistory/index.js +56 -0
- package/lib/screens/ChatHistory/index.js.map +1 -0
- package/lib/screens/Home/HomeScreen.js +136 -427
- package/lib/screens/Home/HomeScreen.js.map +1 -1
- package/lib/screens/Home/components/ChatHistoryLanding.js +436 -214
- package/lib/screens/Home/components/ChatHistoryLanding.js.map +1 -1
- package/package.json +4 -4
package/lib/hooks/useChatApi.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {SortEnum,RoomType,PostTypeEnum,AiAgentMessageRole}from'common';import {useAddChannelMutation,useSendMessagesMutation,GetChannelsByUserWithLastMessageDocument,
|
|
1
|
+
import {SortEnum,RoomType,PostTypeEnum,AiAgentMessageRole}from'common';import {useGetChannelsByUserWithLastMessageQuery,useAddChannelMutation,useSendMessagesMutation,GetChannelsByUserWithLastMessageDocument,useMessagesQuery}from'common/graphql';import {useMemo,useCallback}from'react';import {v4}from'uuid';var __defProp = Object.defineProperty;
|
|
2
2
|
var __defProps = Object.defineProperties;
|
|
3
3
|
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
4
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
@@ -41,50 +41,135 @@ const AI_ASSISTANT_CHANNELS_QUERY_VARS = {
|
|
|
41
41
|
value: SortEnum.Desc
|
|
42
42
|
}
|
|
43
43
|
};
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
const HISTORY_PAGE_SIZE = 20;
|
|
45
|
+
function getHistoryChannelsQueryVariables(orgName, options) {
|
|
46
|
+
var _a, _b;
|
|
47
|
+
const trimmedOrg = typeof orgName === "string" && orgName.trim().length > 0 ? orgName.trim() : void 0;
|
|
48
|
+
return {
|
|
49
|
+
criteria: __spreadValues({
|
|
50
|
+
type: RoomType.Aiassistant
|
|
51
|
+
}, trimmedOrg ? {
|
|
52
|
+
orgName: trimmedOrg
|
|
53
|
+
} : {}),
|
|
54
|
+
limit: (_a = options == null ? void 0 : options.limit) != null ? _a : HISTORY_PAGE_SIZE,
|
|
55
|
+
skip: (_b = options == null ? void 0 : options.skip) != null ? _b : 0,
|
|
56
|
+
sort: {
|
|
57
|
+
key: "updatedAt",
|
|
58
|
+
value: SortEnum.Desc
|
|
59
|
+
}
|
|
60
|
+
};
|
|
47
61
|
}
|
|
48
|
-
|
|
49
|
-
|
|
62
|
+
const HISTORY_QUERY_BASE = getHistoryChannelsQueryVariables();
|
|
63
|
+
function getLastMessageRole(lastMessage) {
|
|
64
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
65
|
+
return String((_h = (_g = (_e = (_b = (_a = lastMessage == null ? void 0 : lastMessage.propsConfiguration) == null ? void 0 : _a.contents) == null ? void 0 : _b.role) != null ? _e : (_d = (_c = lastMessage == null ? void 0 : lastMessage.propsConfiguration) == null ? void 0 : _c.content) == null ? void 0 : _d.role) != null ? _g : (_f = lastMessage == null ? void 0 : lastMessage.props) == null ? void 0 : _f.role) != null ? _h : "").toUpperCase();
|
|
50
66
|
}
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
return
|
|
67
|
+
function getParentUserPrompt(lastMessage) {
|
|
68
|
+
var _a, _b, _c;
|
|
69
|
+
const parent = (_b = (_a = lastMessage == null ? void 0 : lastMessage.propsConfiguration) == null ? void 0 : _a.contents) == null ? void 0 : _b.parent;
|
|
70
|
+
if (!parent) return "";
|
|
71
|
+
return String((_c = parent == null ? void 0 : parent.message) != null ? _c : "").trim();
|
|
55
72
|
}
|
|
56
|
-
function
|
|
73
|
+
function detectMode(channel) {
|
|
74
|
+
var _a, _b;
|
|
75
|
+
const display = String((_a = channel == null ? void 0 : channel.displayName) != null ? _a : "").toLowerCase();
|
|
76
|
+
const title = String((_b = channel == null ? void 0 : channel.title) != null ? _b : "").toLowerCase();
|
|
77
|
+
if (display.startsWith("deep-search") || title.startsWith("deep search") || title.startsWith("deep-search")) {
|
|
78
|
+
return "deep-search";
|
|
79
|
+
}
|
|
80
|
+
return "chat";
|
|
81
|
+
}
|
|
82
|
+
function cleanChannelTitle(rawTitle) {
|
|
83
|
+
const t = String(rawTitle != null ? rawTitle : "").trim();
|
|
84
|
+
if (!t) return "";
|
|
85
|
+
if (/^(chat[\s-]channel|deep[\s-]search)[\s-][0-9a-f][0-9a-f\s-]{7,}\.?$/i.test(t)) return "";
|
|
86
|
+
return t;
|
|
87
|
+
}
|
|
88
|
+
function buildSessionFromChannel(channel) {
|
|
89
|
+
var _a, _b, _c;
|
|
90
|
+
const channelId = String((_a = channel == null ? void 0 : channel.id) != null ? _a : "");
|
|
91
|
+
if (!channelId) return null;
|
|
92
|
+
const lastMessage = (_b = channel == null ? void 0 : channel.lastMessage) != null ? _b : null;
|
|
93
|
+
const lastMessageRole = getLastMessageRole(lastMessage);
|
|
94
|
+
const parentUserPrompt = getParentUserPrompt(lastMessage);
|
|
95
|
+
const parentTrimmed = parentUserPrompt.trim();
|
|
96
|
+
const userTurn = lastMessageRole === "USER" && (lastMessage == null ? void 0 : lastMessage.message) ? String(lastMessage.message).trim() : "";
|
|
97
|
+
const cleanedChannelTitle = cleanChannelTitle(channel == null ? void 0 : channel.title);
|
|
98
|
+
const cleanedDisplayName = cleanChannelTitle(channel == null ? void 0 : channel.displayName);
|
|
99
|
+
let resolvedTitle = parentTrimmed || userTurn || cleanedChannelTitle || cleanedDisplayName;
|
|
100
|
+
const isPlaceholder = !resolvedTitle;
|
|
101
|
+
if (isPlaceholder) resolvedTitle = "Thinking\u2026";
|
|
102
|
+
const rawPreview = String((_c = lastMessage == null ? void 0 : lastMessage.message) != null ? _c : "").replace(/\s+/g, " ").trim();
|
|
103
|
+
let preview = rawPreview;
|
|
104
|
+
if (preview && preview === parentTrimmed) preview = "";
|
|
105
|
+
const sortAt = (() => {
|
|
106
|
+
const candidates = [channel == null ? void 0 : channel.updatedAt, lastMessage == null ? void 0 : lastMessage.updatedAt, lastMessage == null ? void 0 : lastMessage.createdAt, channel == null ? void 0 : channel.createdAt];
|
|
107
|
+
for (const candidate of candidates) {
|
|
108
|
+
if (candidate) {
|
|
109
|
+
const t = new Date(candidate).getTime();
|
|
110
|
+
if (Number.isFinite(t) && t > 0) return t;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return Date.now();
|
|
114
|
+
})();
|
|
115
|
+
const createdAtRaw = (channel == null ? void 0 : channel.createdAt) ? new Date(channel.createdAt).getTime() : sortAt;
|
|
116
|
+
return {
|
|
117
|
+
channelId,
|
|
118
|
+
title: resolvedTitle,
|
|
119
|
+
preview,
|
|
120
|
+
mode: detectMode(channel),
|
|
121
|
+
updatedAt: new Date(sortAt),
|
|
122
|
+
createdAt: new Date(Number.isFinite(createdAtRaw) ? createdAtRaw : sortAt),
|
|
123
|
+
isPlaceholder
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function chatHistorySessionsFromChannels(data) {
|
|
127
|
+
var _a;
|
|
128
|
+
const channels = (_a = data == null ? void 0 : data.channelsByUser) != null ? _a : [];
|
|
129
|
+
return channels.filter((c) => Boolean(c == null ? void 0 : c.id) && (!(c == null ? void 0 : c.type) || c.type === RoomType.Aiassistant)).map((c) => buildSessionFromChannel(c)).filter((row) => row !== null).sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());
|
|
130
|
+
}
|
|
131
|
+
function useChatHistorySessionsFromChannels(orgName, options) {
|
|
132
|
+
var _a, _b;
|
|
133
|
+
const skip = (options == null ? void 0 : options.skip) || !orgName;
|
|
134
|
+
const variables = useMemo(() => getHistoryChannelsQueryVariables(orgName), [orgName]);
|
|
57
135
|
const {
|
|
58
136
|
data,
|
|
59
137
|
loading,
|
|
60
138
|
error,
|
|
61
139
|
refetch
|
|
62
140
|
} = useGetChannelsByUserWithLastMessageQuery({
|
|
63
|
-
variables
|
|
64
|
-
skip
|
|
65
|
-
fetchPolicy: "cache-and-network"
|
|
141
|
+
variables,
|
|
142
|
+
skip,
|
|
143
|
+
fetchPolicy: "cache-and-network",
|
|
144
|
+
notifyOnNetworkStatusChange: true,
|
|
145
|
+
context: {
|
|
146
|
+
cacheKey: "chat-history-channels-list"
|
|
147
|
+
}
|
|
66
148
|
});
|
|
67
|
-
const sessions = useMemo(() =>
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return channels.filter((c) => Boolean(c == null ? void 0 : c.id)).map((channel) => {
|
|
71
|
-
var _a2, _b;
|
|
72
|
-
return {
|
|
73
|
-
id: channel.id,
|
|
74
|
-
title: channel.title || channel.displayName || "New Chat",
|
|
75
|
-
createdAt: new Date((_a2 = channel.createdAt) != null ? _a2 : Date.now()),
|
|
76
|
-
updatedAt: new Date((_b = channel.updatedAt) != null ? _b : Date.now()),
|
|
77
|
-
messageCount: void 0
|
|
78
|
-
};
|
|
79
|
-
});
|
|
80
|
-
}, [data]);
|
|
149
|
+
const sessions = useMemo(() => chatHistorySessionsFromChannels(data), [data]);
|
|
150
|
+
const sourceChannelCount = (_b = (_a = data == null ? void 0 : data.channelsByUser) == null ? void 0 : _a.length) != null ? _b : 0;
|
|
151
|
+
const sessionsLoaded = data !== void 0;
|
|
81
152
|
return {
|
|
82
153
|
sessions,
|
|
83
154
|
loading,
|
|
155
|
+
sessionsLoaded,
|
|
84
156
|
error,
|
|
85
|
-
refetch
|
|
157
|
+
refetch,
|
|
158
|
+
sourceChannelCount
|
|
86
159
|
};
|
|
87
160
|
}
|
|
161
|
+
function stripModelCostHeader(content) {
|
|
162
|
+
const normalized = content.replace(/\r\n/g, "\n");
|
|
163
|
+
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, "");
|
|
164
|
+
}
|
|
165
|
+
function sanitizeAssistantContentByRole(role, content) {
|
|
166
|
+
return role === "assistant" ? stripModelCostHeader(content) : content;
|
|
167
|
+
}
|
|
168
|
+
function omitContent(value) {
|
|
169
|
+
const clone = __spreadValues({}, value != null ? value : {});
|
|
170
|
+
delete clone.content;
|
|
171
|
+
return clone;
|
|
172
|
+
}
|
|
88
173
|
function mapPostToChatMessageUI(post, fallbackChannelId) {
|
|
89
174
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
|
|
90
175
|
const props = (_a = post.props) != null ? _a : {};
|
|
@@ -133,10 +218,17 @@ function useChatMessages(sessionId, options) {
|
|
|
133
218
|
},
|
|
134
219
|
skip: !sessionId || (void 0 ),
|
|
135
220
|
fetchPolicy: "cache-and-network",
|
|
221
|
+
notifyOnNetworkStatusChange: true,
|
|
222
|
+
/**
|
|
223
|
+
* Cache key is per-channel so switching sessions doesn't read another channel's response.
|
|
224
|
+
* Keeping this as a constant ('messages-list') used to cause cross-session bleed in the
|
|
225
|
+
* custom Apollo link before reaching the normalized cache.
|
|
226
|
+
*/
|
|
136
227
|
context: {
|
|
137
|
-
cacheKey: "messages-list"
|
|
228
|
+
cacheKey: sessionId ? `messages-list:${sessionId}` : "messages-list"
|
|
138
229
|
}
|
|
139
230
|
});
|
|
231
|
+
const messagesLoaded = data !== void 0;
|
|
140
232
|
const messages = useMemo(() => {
|
|
141
233
|
var _a, _b;
|
|
142
234
|
if (!sessionId) return [];
|
|
@@ -146,6 +238,7 @@ function useChatMessages(sessionId, options) {
|
|
|
146
238
|
return {
|
|
147
239
|
messages,
|
|
148
240
|
loading,
|
|
241
|
+
messagesLoaded,
|
|
149
242
|
error,
|
|
150
243
|
refetch
|
|
151
244
|
};
|
|
@@ -192,9 +285,27 @@ function useChatMutations() {
|
|
|
192
285
|
} : {}), projectId ? {
|
|
193
286
|
projectId
|
|
194
287
|
} : {}),
|
|
288
|
+
/**
|
|
289
|
+
* Refetch every cache slot the rest of the app is watching for
|
|
290
|
+
* channel lists. Apollo keys cached results by `variables`, so each
|
|
291
|
+
* shape we emit here must match a watched query exactly.
|
|
292
|
+
*
|
|
293
|
+
* Variants:
|
|
294
|
+
* 1. Legacy limit:100 list (web parity, no `criteria.orgName`).
|
|
295
|
+
* 2. Mobile history-screen variant WITH `criteria.orgName` so the
|
|
296
|
+
* resolver's `$in: [slug, orgId]` matches mobile-created channels.
|
|
297
|
+
* 3. Same variant WITHOUT orgName, in case the screen mounted before
|
|
298
|
+
* org settings resolved.
|
|
299
|
+
*/
|
|
195
300
|
refetchQueries: [{
|
|
196
301
|
query: GetChannelsByUserWithLastMessageDocument,
|
|
197
302
|
variables: AI_ASSISTANT_CHANNELS_QUERY_VARS
|
|
303
|
+
}, ...orgName ? [{
|
|
304
|
+
query: GetChannelsByUserWithLastMessageDocument,
|
|
305
|
+
variables: getHistoryChannelsQueryVariables(orgName)
|
|
306
|
+
}] : [], {
|
|
307
|
+
query: GetChannelsByUserWithLastMessageDocument,
|
|
308
|
+
variables: HISTORY_QUERY_BASE
|
|
198
309
|
}],
|
|
199
310
|
awaitRefetchQueries: true
|
|
200
311
|
});
|
|
@@ -212,7 +323,7 @@ function useChatMutations() {
|
|
|
212
323
|
};
|
|
213
324
|
}, [addChannelMutation]);
|
|
214
325
|
const saveMessages = useCallback(async (input) => {
|
|
215
|
-
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
326
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
216
327
|
const sanitizedAssistantContent = stripModelCostHeader((_a = input.assistantMessage.content) != null ? _a : "");
|
|
217
328
|
const assistantMessageWithoutContent = omitContent((_b = input.assistantMessage) != null ? _b : {});
|
|
218
329
|
const userResult = await sendMessagesMutation({
|
|
@@ -234,28 +345,34 @@ function useChatMutations() {
|
|
|
234
345
|
} : {})
|
|
235
346
|
})
|
|
236
347
|
});
|
|
348
|
+
const userPostId = (_g = (_f = (_e = userResult.data) == null ? void 0 : _e.sendMessage) == null ? void 0 : _f.id) != null ? _g : null;
|
|
237
349
|
const assistantResult = await sendMessagesMutation({
|
|
238
|
-
variables: {
|
|
350
|
+
variables: __spreadProps(__spreadValues({
|
|
239
351
|
channelId: input.sessionId,
|
|
240
352
|
type: RoomType.Aiassistant,
|
|
241
|
-
content: sanitizedAssistantContent
|
|
242
|
-
|
|
353
|
+
content: sanitizedAssistantContent
|
|
354
|
+
}, userPostId ? {
|
|
355
|
+
postId: userPostId
|
|
356
|
+
} : {}), {
|
|
357
|
+
extraProps: __spreadValues(__spreadValues(__spreadValues({
|
|
243
358
|
type: PostTypeEnum.Aiassistant,
|
|
244
359
|
role: "assistant",
|
|
245
|
-
attachments: (
|
|
360
|
+
attachments: (_h = input.assistantMessage.attachments) != null ? _h : [],
|
|
246
361
|
tokenCount: input.assistantMessage.tokenCount,
|
|
247
362
|
latencyMs: input.assistantMessage.latencyMs,
|
|
248
363
|
model: input.assistantMessage.model,
|
|
249
|
-
finishReason: (
|
|
364
|
+
finishReason: (_i = input.assistantMessage.finishReason) != null ? _i : null,
|
|
250
365
|
isActive: true,
|
|
251
366
|
status: "complete"
|
|
252
|
-
},
|
|
367
|
+
}, userPostId ? {
|
|
368
|
+
parentId: userPostId
|
|
369
|
+
} : {}), assistantMessageWithoutContent), input.mode ? {
|
|
253
370
|
mode: input.mode
|
|
254
371
|
} : {})
|
|
255
|
-
}
|
|
372
|
+
})
|
|
256
373
|
});
|
|
257
|
-
const userPost = (
|
|
258
|
-
const assistantPost = (
|
|
374
|
+
const userPost = (_j = userResult.data) == null ? void 0 : _j.sendMessage;
|
|
375
|
+
const assistantPost = (_k = assistantResult.data) == null ? void 0 : _k.sendMessage;
|
|
259
376
|
if (!userPost || !assistantPost) {
|
|
260
377
|
throw new Error("Failed to send messages");
|
|
261
378
|
}
|
|
@@ -280,4 +397,4 @@ function useChatMutations() {
|
|
|
280
397
|
saveMessages: sendMessagesLoading
|
|
281
398
|
}
|
|
282
399
|
};
|
|
283
|
-
}export{AI_ASSISTANT_CHANNELS_QUERY_VARS,useChatMessages,useChatMutations
|
|
400
|
+
}export{AI_ASSISTANT_CHANNELS_QUERY_VARS,HISTORY_PAGE_SIZE,HISTORY_QUERY_BASE,buildSessionFromChannel,chatHistorySessionsFromChannels,getHistoryChannelsQueryVariables,useChatHistorySessionsFromChannels,useChatMessages,useChatMutations};//# sourceMappingURL=useChatApi.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useChatApi.js","sources":["../../src/hooks/useChatApi.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { AiAgentMessageRole, PostTypeEnum, RoomType, SortEnum } from 'common';\nimport {\n GetChannelsByUserWithLastMessageDocument,\n useAddChannelMutation,\n useGetChannelsByUserWithLastMessageQuery,\n useMessagesQuery,\n useSendMessagesMutation,\n} from 'common/graphql';\nimport type {\n IAccountCreateChatSessionInput,\n IAccountSaveChatMessagesInput as IAccountSaveChatMessagesInputBase,\n} from 'common/server';\nimport { useCallback, useMemo } from 'react';\nimport { v4 as uuidv4 } from 'uuid';\n\nconst MESSAGES_PAGE_LIMIT = 100;\n\n/** Same variables as web Inbox / AIAgent: list AI assistant channels for the current user. */\nexport const AI_ASSISTANT_CHANNELS_QUERY_VARS = {\n criteria: { type: RoomType.Aiassistant },\n limit: 100,\n skip: 0,\n sort: { key: 'updatedAt', value: SortEnum.Desc },\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\nfunction sanitizeAssistantContentByRole(role: unknown, content: string): string {\n return role === 'assistant' ? stripModelCostHeader(content) : content;\n}\n\nfunction omitContent<T extends Record<string, any>>(value: T | null | undefined): Omit<T, 'content'> {\n const clone = { ...(value ?? {}) } as Record<string, any>;\n delete clone.content;\n return clone as Omit<T, 'content'>;\n}\n\nexport interface ChatSessionUI {\n id: string;\n title: string;\n createdAt: Date;\n updatedAt: Date;\n messageCount?: number;\n}\n\nexport function useChatSessions(options?: { includeArchived?: boolean; skip?: boolean }) {\n const { data, loading, error, refetch } = useGetChannelsByUserWithLastMessageQuery({\n variables: AI_ASSISTANT_CHANNELS_QUERY_VARS,\n skip: options?.skip,\n fetchPolicy: 'cache-and-network',\n });\n\n const sessions: ChatSessionUI[] = useMemo(() => {\n const channels = data?.channelsByUser ?? [];\n return channels\n .filter((c): c is NonNullable<typeof c> => Boolean(c?.id))\n .map((channel) => ({\n id: channel.id,\n title: channel.title || channel.displayName || 'New Chat',\n createdAt: new Date(channel.createdAt ?? Date.now()),\n updatedAt: new Date(channel.updatedAt ?? Date.now()),\n messageCount: undefined,\n }));\n }, [data]);\n\n return { sessions, loading, error, refetch };\n}\n\nexport interface ChatMessageUI {\n id: string;\n sessionId: string;\n role: 'user' | 'assistant' | 'system';\n content: string;\n attachments?: Array<{ id: string; name: string; type: string; mimeType?: string; size?: number; url?: string }>;\n tokenCount?: number;\n model?: string;\n createdAt: Date;\n updatedAt: Date;\n}\n\ninterface MinimalFile {\n id?: string | null;\n name?: string | null;\n mimeType?: string | null;\n size?: number | null;\n url?: string | null;\n}\n\ninterface MinimalPost {\n id?: string | null;\n message?: string | null;\n createdAt?: string | null;\n updatedAt?: string | null;\n channel?: { id?: string | null } | null;\n files?: { data?: MinimalFile[] | null } | null;\n props?: { role?: string | null; tokenCount?: number | null; model?: string | null } | null;\n propsConfiguration?: {\n contents?: { role?: string | null } | null;\n content?: { role?: string | null } | null;\n } | null;\n}\n\nfunction mapPostToChatMessageUI(post: MinimalPost, fallbackChannelId: string): ChatMessageUI {\n const props = (post.props ?? {}) as Record<string, any>;\n const contents = post.propsConfiguration?.contents ?? {};\n const roleRaw = props.role ?? contents.role ?? post.propsConfiguration?.content?.role;\n let role: ChatMessageUI['role'] = 'assistant';\n if (roleRaw === 'user' || roleRaw === AiAgentMessageRole.User) role = 'user';\n else if (roleRaw === 'assistant' || roleRaw === AiAgentMessageRole.Assistant) role = 'assistant';\n else if (roleRaw === 'system') role = 'system';\n\n const rawContent = post?.message ?? '';\n const content = sanitizeAssistantContentByRole(role, rawContent);\n\n return {\n id: post?.id ?? uuidv4(),\n sessionId: post?.channel?.id ?? fallbackChannelId,\n role,\n content,\n attachments: (post?.files?.data ?? []).map((file) => ({\n id: file.id ?? uuidv4(),\n name: file.name ?? 'file',\n type: typeof file.mimeType === 'string' && file.mimeType.startsWith('image/') ? 'screenshot' : 'file',\n mimeType: file.mimeType ?? undefined,\n size: file.size ?? undefined,\n url: file.url ?? undefined,\n })),\n tokenCount: props.tokenCount ?? undefined,\n model: props.model ?? undefined,\n createdAt: post?.createdAt ? new Date(post.createdAt) : new Date(),\n updatedAt: post?.updatedAt ? new Date(post.updatedAt) : new Date(),\n };\n}\n\nexport function useChatMessages(sessionId: string | null, options?: { skip?: boolean }) {\n const { data, loading, error, refetch } = useMessagesQuery({\n variables: {\n channelId: sessionId ?? undefined,\n parentId: null,\n limit: MESSAGES_PAGE_LIMIT,\n skip: 0,\n },\n skip: !sessionId || options?.skip,\n fetchPolicy: 'cache-and-network',\n context: { cacheKey: 'messages-list' },\n });\n\n const messages: ChatMessageUI[] = useMemo(() => {\n if (!sessionId) return [];\n const rows = data?.messages?.data ?? [];\n return rows\n .map((post) => mapPostToChatMessageUI(post as MinimalPost, sessionId))\n .sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());\n }, [data, sessionId]);\n\n return { messages, loading, error, refetch };\n}\n\nexport type IAccountSaveChatMessagesInput = IAccountSaveChatMessagesInputBase & {\n mode?: 'plan' | 'build';\n createdBy?: string;\n};\n\nexport function useChatMutations() {\n const [addChannelMutation, { loading: createChannelLoading }] = useAddChannelMutation();\n const [sendMessagesMutation, { loading: sendMessagesLoading }] = useSendMessagesMutation();\n\n const createChannel = useCallback(\n async (input?: IAccountCreateChatSessionInput): Promise<ChatSessionUI> => {\n const {\n orgName: orgNameArg,\n projectId: projectIdArg,\n ...inputForSettings\n } = (input ?? {}) as IAccountCreateChatSessionInput & {\n orgName?: string | null;\n projectId?: string | null;\n };\n const orgName =\n typeof orgNameArg === 'string' && orgNameArg.trim().length > 0 ? orgNameArg.trim() : undefined;\n const projectId =\n typeof projectIdArg === 'string' && projectIdArg.trim().length > 0 ? projectIdArg.trim() : undefined;\n\n const settings = {\n title: input?.title ?? 'New Chat',\n description: input?.systemPrompt ?? null,\n isShared: false,\n sharedSlug: null,\n isArchived: false,\n isPinned: false,\n model: input?.model ?? null,\n systemPrompt: input?.systemPrompt ?? null,\n ...inputForSettings,\n };\n\n const { data } = await addChannelMutation({\n variables: {\n channelId: input?.id ?? null,\n name: input?.title ?? 'New Chat',\n description: input?.systemPrompt ?? null,\n type: RoomType.Aiassistant,\n settings,\n ...(orgName ? { orgName } : {}),\n ...(projectId ? { projectId } : {}),\n },\n refetchQueries: [\n { query: GetChannelsByUserWithLastMessageDocument, variables: AI_ASSISTANT_CHANNELS_QUERY_VARS },\n ],\n awaitRefetchQueries: true,\n });\n\n if (!data?.createChannel?.id) {\n throw new Error('Failed to create channel');\n }\n\n const channel = data.createChannel;\n const title = channel.title ?? input?.title ?? 'New Chat';\n const now = new Date();\n\n return {\n id: channel.id,\n title,\n createdAt: now,\n updatedAt: now,\n };\n },\n [addChannelMutation],\n );\n\n const saveMessages = useCallback(\n async (\n input: IAccountSaveChatMessagesInput,\n ): Promise<{\n userMessage: ChatMessageUI;\n assistantMessage: ChatMessageUI;\n session: ChatSessionUI;\n }> => {\n const sanitizedAssistantContent = stripModelCostHeader(input.assistantMessage.content ?? '');\n const assistantMessageWithoutContent = omitContent((input.assistantMessage as any) ?? {});\n const userResult = await sendMessagesMutation({\n variables: {\n channelId: input.sessionId,\n type: RoomType.Aiassistant,\n content: input.userMessage.content ?? '',\n ...(input.createdBy ? { createdBy: input.createdBy } : {}),\n extraProps: {\n type: PostTypeEnum.Aiassistant,\n role: 'user',\n attachments: input.userMessage.attachments ?? [],\n isActive: true,\n status: 'complete',\n ...(input.userMessage as any),\n ...(input.mode ? { mode: input.mode } : {}),\n },\n } as any,\n });\n const assistantResult = await sendMessagesMutation({\n variables: {\n channelId: input.sessionId,\n type: RoomType.Aiassistant,\n content: sanitizedAssistantContent,\n extraProps: {\n type: PostTypeEnum.Aiassistant,\n role: 'assistant',\n attachments: input.assistantMessage.attachments ?? [],\n tokenCount: input.assistantMessage.tokenCount,\n latencyMs: input.assistantMessage.latencyMs,\n model: input.assistantMessage.model,\n finishReason: (input.assistantMessage as any).finishReason ?? null,\n isActive: true,\n status: 'complete',\n ...assistantMessageWithoutContent,\n ...(input.mode ? { mode: input.mode } : {}),\n },\n } as any,\n });\n\n const userPost = userResult.data?.sendMessage;\n const assistantPost = assistantResult.data?.sendMessage;\n if (!userPost || !assistantPost) {\n throw new Error('Failed to send messages');\n }\n\n const now = new Date();\n return {\n userMessage: mapPostToChatMessageUI(userPost as MinimalPost, input.sessionId),\n assistantMessage: mapPostToChatMessageUI(assistantPost as MinimalPost, input.sessionId),\n session: {\n id: input.sessionId,\n title: 'Chat',\n createdAt: now,\n updatedAt: now,\n },\n };\n },\n [sendMessagesMutation],\n );\n\n return {\n createChannel,\n createSession: createChannel,\n saveMessages,\n loading: { create: createChannelLoading, saveMessages: sendMessagesLoading },\n };\n}\n"],"names":["_a","uuidv4","_b","_c","_d","_e"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useChatApi.js","sources":["../../src/hooks/useChatApi.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\nimport { AiAgentMessageRole, PostTypeEnum, RoomType, SortEnum } from 'common';\nimport {\n GetChannelsByUserWithLastMessageDocument,\n useAddChannelMutation,\n useGetChannelsByUserWithLastMessageQuery,\n useMessagesQuery,\n useSendMessagesMutation,\n} from 'common/graphql';\nimport type {\n IAccountCreateChatSessionInput,\n IAccountSaveChatMessagesInput as IAccountSaveChatMessagesInputBase,\n} from 'common/server';\nimport { useCallback, useMemo } from 'react';\nimport { v4 as uuidv4 } from 'uuid';\n\nconst MESSAGES_PAGE_LIMIT = 100;\n\n/** Same variables as web Inbox / AIAgent: list AI assistant channels for the current user. */\nexport const AI_ASSISTANT_CHANNELS_QUERY_VARS = {\n criteria: { type: RoomType.Aiassistant },\n limit: 100,\n skip: 0,\n sort: { key: 'updatedAt', value: SortEnum.Desc },\n};\n\nexport const HISTORY_PAGE_SIZE = 20;\n\n/**\n * Variables for the channels-based chat history list (`ChatHistoryLanding`).\n *\n * IMPORTANT: pass the user's org `slug` (e.g. `tarun-upadhyay-qraw`) so the\n * `channelsByUser` resolver's `$in: [criteria.orgName, orgId]` includes\n * channels stored under the slug. When `criteria.orgName` is omitted, the\n * `$in` collapses to just `[orgId]` and channels saved with the slug as\n * `orgName` (the mobile create path) never match. That's the cause of the\n * silently-empty history screen.\n *\n * Kept as a builder (not a constant) because the slug varies per user and\n * because Apollo treats different `variables` as different cached entries —\n * if the create mutation refetches a no-orgName variant, the orgName-variant\n * the screen watches stays stale.\n */\nexport function getHistoryChannelsQueryVariables(orgName?: string | null, options?: { skip?: number; limit?: number }) {\n const trimmedOrg = typeof orgName === 'string' && orgName.trim().length > 0 ? orgName.trim() : undefined;\n return {\n criteria: {\n type: RoomType.Aiassistant,\n ...(trimmedOrg ? { orgName: trimmedOrg } : {}),\n },\n limit: options?.limit ?? HISTORY_PAGE_SIZE,\n skip: options?.skip ?? 0,\n sort: { key: 'updatedAt' as const, value: SortEnum.Desc },\n };\n}\n\n/** @deprecated Use {@link getHistoryChannelsQueryVariables} so `orgName` is included. */\nexport const HISTORY_QUERY_BASE = getHistoryChannelsQueryVariables();\n\n/**\n * Variables for the chat-history feed on the mobile `ChatHistory` screen.\n *\n * First page uses `HISTORY_PAGE_SIZE` (20) posts; \"Load older\" paginates by post\n * `skip` in increments of 20. Rows are still one per channel (collapsed from posts).\n *\n * This query intentionally hits `messages` (not `channelsByUser`) — the same\n * pattern the web sidebar uses (`useNewChatPageHistorySessions`). Reasons:\n * 1. `channelsByUser` is server-side gated by an injected `orgName` /\n * `members` filter that can mismatch when channels were stored with an\n * org slug while the resolver injects the org id. The `messages`\n * resolver filters Post directly by `editedBy: accountId`, so the\n * user's own AI-assistant posts always show up.\n * 2. The user-authored post IS the conversation's natural title — no need\n * to walk `lastMessage.propsConfiguration.contents.parent` to recover\n * the original prompt.\n *\n * - `type: AIASSISTANT` scopes to AI chat (not direct/service rooms).\n * - `props.role: 'user'` selects only the user's turns. The assistant reply\n * is ignored here; it would override the title with the agent's words.\n * - `editedBy: accountUserId` scopes to the current user's own posts,\n * independent of channel membership / org name.\n */\nexport function getChatHistoryMessagesQueryVariables(\n accountUserId: string,\n options?: { skip?: number; limit?: number },\n) {\n return {\n limit: options?.limit ?? HISTORY_PAGE_SIZE,\n skip: options?.skip ?? 0,\n sort: { key: 'updatedAt' as const, value: SortEnum.Desc },\n type: PostTypeEnum.Aiassistant,\n editedBy: accountUserId,\n props: { role: 'user' },\n };\n}\n\nexport type ChatHistoryMode = 'chat' | 'deep-search';\n\nexport interface ChatHistorySession {\n /** Channel id — used to navigate to the Chat screen. */\n channelId: string;\n /** User's most recent prompt in this channel (used as the row title). */\n title: string;\n /** Second line: latest post `message` field (same as Manus subtitle). */\n preview: string;\n /** Conversation mode (chat / deep-search), inferred from channel display name / title. */\n mode: ChatHistoryMode;\n /** Most-recent activity timestamp (sort key + bucket key for Today/Yesterday/…). */\n updatedAt: Date;\n createdAt: Date;\n /**\n * True when no concrete prompt was recoverable (no parent, no user turn, no\n * meaningful channel.title). UI renders the title in a quieter style.\n */\n isPlaceholder: boolean;\n}\n\n/**\n * Collapse a list of user-authored AI assistant posts (newest first) into one\n * row per channel. First post per `channel.id` wins the title, which — because\n * the query is sorted by `updatedAt DESC` — is the user's latest prompt in\n * that channel. Posts whose `channel.id` is missing (unexpected, but possible\n * if the resolver omits the relation) are skipped.\n */\nexport function chatHistorySessionsFromMessages(\n data: { messages?: { data?: unknown[] | null } | null } | null | undefined,\n): ChatHistorySession[] {\n const rows = data?.messages?.data;\n if (!rows?.length) return [];\n\n const seen = new Set<string>();\n const sessions: ChatHistorySession[] = [];\n\n for (const post of rows as any[]) {\n const channelId = post?.channel?.id ? String(post.channel.id) : '';\n if (channelId && !seen.has(channelId)) {\n seen.add(channelId);\n\n const rawTitle = String(post?.message ?? '')\n .replace(/\\s+/g, ' ')\n .trim();\n const updatedAt = post?.updatedAt ? new Date(post.updatedAt) : new Date();\n const createdAt = post?.createdAt ? new Date(post.createdAt) : updatedAt;\n const title = rawTitle || 'New chat';\n\n sessions.push({\n channelId,\n title,\n preview: '',\n mode: 'chat',\n updatedAt,\n createdAt,\n isPlaceholder: !rawTitle,\n });\n }\n }\n\n return sessions;\n}\n\n/**\n * Mobile parity hook for the web sidebar's `useNewChatPageHistorySessions`.\n *\n * Returns one row per channel where the user has authored at least one AI assistant\n * post, with the title taken from that user's latest prompt. Skipped when\n * `accountUserId` isn't known yet (we don't want to fire a query without it).\n */\nexport function useChatHistorySessionsFromMessages(\n accountUserId: string | null | undefined,\n options?: { skip?: boolean },\n) {\n const skip = options?.skip || !accountUserId;\n const { data, loading, error, refetch } = useMessagesQuery({\n variables: accountUserId ? getChatHistoryMessagesQueryVariables(accountUserId) : undefined,\n skip,\n fetchPolicy: 'cache-and-network',\n notifyOnNetworkStatusChange: true,\n context: { cacheKey: 'new-chat-history-messages' },\n });\n\n const sessions = useMemo(() => chatHistorySessionsFromMessages(data), [data]);\n const sourcePostCount = data?.messages?.data?.length ?? 0;\n\n return { sessions, loading, error, refetch, sourcePostCount };\n}\n\n/* -------------------------------------------------------------------------- */\n/* Channels-based chat history (parent + lastMessage) */\n/* -------------------------------------------------------------------------- */\n\ninterface ChannelLastMessageLike {\n message?: string | null;\n createdAt?: string | null;\n updatedAt?: string | null;\n props?: { role?: string | null } | null;\n propsConfiguration?: {\n contents?: {\n role?: string | null;\n parent?: {\n message?: string | null;\n props?: { role?: string | null } | null;\n } | null;\n } | null;\n content?: { role?: string | null } | null;\n } | null;\n}\n\ninterface ChannelLike {\n id?: string | null;\n type?: string | null;\n displayName?: string | null;\n title?: string | null;\n createdAt?: string | null;\n updatedAt?: string | null;\n lastMessage?: ChannelLastMessageLike | null;\n}\n\nfunction getLastMessageRole(lastMessage: ChannelLastMessageLike | null | undefined): string {\n return String(\n lastMessage?.propsConfiguration?.contents?.role ??\n lastMessage?.propsConfiguration?.content?.role ??\n lastMessage?.props?.role ??\n '',\n ).toUpperCase();\n}\n\nfunction getParentUserPrompt(lastMessage: ChannelLastMessageLike | null | undefined): string {\n const parent = lastMessage?.propsConfiguration?.contents?.parent;\n if (!parent) return '';\n return String(parent?.message ?? '').trim();\n}\n\nfunction detectMode(channel: ChannelLike): ChatHistoryMode {\n const display = String(channel?.displayName ?? '').toLowerCase();\n const title = String(channel?.title ?? '').toLowerCase();\n if (display.startsWith('deep-search') || title.startsWith('deep search') || title.startsWith('deep-search')) {\n return 'deep-search';\n }\n return 'chat';\n}\n\n/**\n * Drop the internal slug we use as `channel.title` for server-side mode detection\n * (`chat-channel-<uuid>` / `deep-search-<uuid>`) so it doesn't leak into the row\n * label. The server sometimes also reformats this slug into `displayName` as\n * title-cased text with spaces (e.g. `\"Deep Search b64be4f7 9fe6 …\"`) — those\n * are equally machine-generated and must NOT be shown to the user.\n *\n * Pattern accepts:\n * • `deep-search-<uuid>` / `chat-channel-<uuid>` (raw, mode signal)\n * • `Deep Search <uuid>` / `Chat Channel <uuid>` (display-cased, server-reformatted)\n * • UUID may use hyphens, spaces, or be partially truncated as long as the\n * trailing chunk is hex.\n */\nfunction cleanChannelTitle(rawTitle: string | null | undefined): string {\n const t = String(rawTitle ?? '').trim();\n if (!t) return '';\n if (/^(chat[\\s-]channel|deep[\\s-]search)[\\s-][0-9a-f][0-9a-f\\s-]{7,}\\.?$/i.test(t)) return '';\n return t;\n}\n\n/**\n * Map one channel into a session row (Manus-style two-line list):\n *\n * **Title (line 1):** `lastMessage.propsConfiguration.contents.parent.message`\n * when present (the user turn the thread is anchored on). Otherwise fall back\n * to the last post body if that post is still a user message, then a\n * machine-slug-stripped channel title, then a machine-slug-stripped\n * `displayName`, then `\"Thinking…\"`. Machine slugs (`deep-search-<uuid>`,\n * `chat-channel-<uuid>`, and their server-reformatted display variants)\n * are filtered via `cleanChannelTitle`, so they never reach the row.\n *\n * **Preview (line 2):** `lastMessage.message` as returned by the API (trimmed,\n * whitespace collapsed). Agent errors that start with `⚠` stay visible in the\n * subtitle, matching the reference UI.\n *\n * If preview text equals the title after trim, the second line is omitted\n * (single-line channel, no duplicate).\n */\nexport function buildSessionFromChannel(channel: ChannelLike): ChatHistorySession | null {\n const channelId = String(channel?.id ?? '');\n if (!channelId) return null;\n\n const lastMessage = channel?.lastMessage ?? null;\n const lastMessageRole = getLastMessageRole(lastMessage);\n const parentUserPrompt = getParentUserPrompt(lastMessage);\n const parentTrimmed = parentUserPrompt.trim();\n\n const userTurn = lastMessageRole === 'USER' && lastMessage?.message ? String(lastMessage.message).trim() : '';\n const cleanedChannelTitle = cleanChannelTitle(channel?.title);\n /**\n * Apply the same machine-slug cleaner to `displayName`. The server\n * sometimes derives displayName from the title (`\"deep-search-<uuid>\"`\n * → `\"Deep Search <uuid>\"`), so without this the slug bypasses\n * `cleanedChannelTitle` and lands directly in the row label.\n */\n const cleanedDisplayName = cleanChannelTitle(channel?.displayName);\n\n let resolvedTitle = parentTrimmed || userTurn || cleanedChannelTitle || cleanedDisplayName;\n const isPlaceholder = !resolvedTitle;\n /**\n * When every signal fails — typical when a send just landed and the\n * server hasn't yet persisted the message that would populate\n * `propsConfiguration.contents.parent.message` — show `\"Thinking…\"`\n * instead of an empty label or the raw machine slug. The row's mode\n * tile still signals chat vs deep-search, so the user has enough\n * context to recognize the entry without leaking implementation noise.\n */\n if (isPlaceholder) resolvedTitle = 'Thinking…';\n\n const rawPreview = String(lastMessage?.message ?? '')\n .replace(/\\s+/g, ' ')\n .trim();\n let preview = rawPreview;\n if (preview && preview === parentTrimmed) preview = '';\n\n const sortAt = (() => {\n const candidates = [channel?.updatedAt, lastMessage?.updatedAt, lastMessage?.createdAt, channel?.createdAt];\n for (const candidate of candidates) {\n if (candidate) {\n const t = new Date(candidate).getTime();\n if (Number.isFinite(t) && t > 0) return t;\n }\n }\n return Date.now();\n })();\n\n const createdAtRaw = channel?.createdAt ? new Date(channel.createdAt).getTime() : sortAt;\n\n return {\n channelId,\n title: resolvedTitle,\n preview,\n mode: detectMode(channel),\n updatedAt: new Date(sortAt),\n createdAt: new Date(Number.isFinite(createdAtRaw) ? createdAtRaw : sortAt),\n isPlaceholder,\n };\n}\n\n/** Collapse a `channelsByUser` response into session rows for the history list. */\nexport function chatHistorySessionsFromChannels(\n data: { channelsByUser?: (ChannelLike | null)[] | null } | null | undefined,\n): ChatHistorySession[] {\n const channels = (data?.channelsByUser ?? []) as (ChannelLike | null)[];\n return channels\n .filter((c): c is ChannelLike => Boolean(c?.id) && (!c?.type || c.type === RoomType.Aiassistant))\n .map((c) => buildSessionFromChannel(c))\n .filter((row): row is ChatHistorySession => row !== null)\n .sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());\n}\n\n/**\n * Chat history feed driven by `channelsByUser`. Each row: parent prompt as title,\n * `lastMessage.message` as subtitle (Manus-style), when the API provides them.\n *\n * Caller MUST pass `orgName` (the org slug). Without it, the resolver only\n * matches channels whose `orgName` field equals the user's `orgId`, which is\n * never the case for mobile-created channels (those store the slug). The hook\n * suspends the query (`skip: true`) until `orgName` is known, so we never\n * fire a guaranteed-empty request.\n *\n * Pagination is by channel count (one channel = one row in this query),\n * unlike the messages-based path which paginates by raw post rows.\n */\nexport function useChatHistorySessionsFromChannels(orgName: string | null | undefined, options?: { skip?: boolean }) {\n const skip = options?.skip || !orgName;\n const variables = useMemo(() => getHistoryChannelsQueryVariables(orgName), [orgName]);\n\n const { data, loading, error, refetch } = useGetChannelsByUserWithLastMessageQuery({\n variables,\n skip,\n fetchPolicy: 'cache-and-network',\n notifyOnNetworkStatusChange: true,\n context: { cacheKey: 'chat-history-channels-list' },\n });\n\n const sessions = useMemo(() => chatHistorySessionsFromChannels(data), [data]);\n const sourceChannelCount = data?.channelsByUser?.length ?? 0;\n /**\n * `sessionsLoaded` means \"we have data we can show\", regardless of whether a\n * background revalidation is still in flight. Same contract as `messagesLoaded`\n * in `useChatMessages` — lets the screen show the cached list (or empty state)\n * immediately on revisit instead of flashing a loader for the network round-trip.\n */\n const sessionsLoaded = data !== undefined;\n\n return { sessions, loading, sessionsLoaded, error, refetch, sourceChannelCount };\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\nfunction sanitizeAssistantContentByRole(role: unknown, content: string): string {\n return role === 'assistant' ? stripModelCostHeader(content) : content;\n}\n\nfunction omitContent<T extends Record<string, any>>(value: T | null | undefined): Omit<T, 'content'> {\n const clone = { ...(value ?? {}) } as Record<string, any>;\n delete clone.content;\n return clone as Omit<T, 'content'>;\n}\n\nexport interface ChatSessionUI {\n id: string;\n title: string;\n createdAt: Date;\n updatedAt: Date;\n messageCount?: number;\n}\n\nexport function useChatSessions(options?: { includeArchived?: boolean; skip?: boolean }) {\n const { data, loading, error, refetch } = useGetChannelsByUserWithLastMessageQuery({\n variables: AI_ASSISTANT_CHANNELS_QUERY_VARS,\n skip: options?.skip,\n fetchPolicy: 'cache-and-network',\n });\n\n const sessions: ChatSessionUI[] = useMemo(() => {\n const channels = data?.channelsByUser ?? [];\n return channels\n .filter((c): c is NonNullable<typeof c> => Boolean(c?.id))\n .map((channel) => ({\n id: channel.id,\n title: channel.title || channel.displayName || 'New Chat',\n createdAt: new Date(channel.createdAt ?? Date.now()),\n updatedAt: new Date(channel.updatedAt ?? Date.now()),\n messageCount: undefined,\n }));\n }, [data]);\n\n return { sessions, loading, error, refetch };\n}\n\nexport interface ChatMessageUI {\n id: string;\n sessionId: string;\n role: 'user' | 'assistant' | 'system';\n content: string;\n attachments?: Array<{ id: string; name: string; type: string; mimeType?: string; size?: number; url?: string }>;\n tokenCount?: number;\n model?: string;\n createdAt: Date;\n updatedAt: Date;\n}\n\ninterface MinimalFile {\n id?: string | null;\n name?: string | null;\n mimeType?: string | null;\n size?: number | null;\n url?: string | null;\n}\n\ninterface MinimalPost {\n id?: string | null;\n message?: string | null;\n createdAt?: string | null;\n updatedAt?: string | null;\n channel?: { id?: string | null } | null;\n files?: { data?: MinimalFile[] | null } | null;\n props?: { role?: string | null; tokenCount?: number | null; model?: string | null } | null;\n propsConfiguration?: {\n contents?: { role?: string | null } | null;\n content?: { role?: string | null } | null;\n } | null;\n}\n\nfunction mapPostToChatMessageUI(post: MinimalPost, fallbackChannelId: string): ChatMessageUI {\n const props = (post.props ?? {}) as Record<string, any>;\n const contents = post.propsConfiguration?.contents ?? {};\n const roleRaw = props.role ?? contents.role ?? post.propsConfiguration?.content?.role;\n let role: ChatMessageUI['role'] = 'assistant';\n if (roleRaw === 'user' || roleRaw === AiAgentMessageRole.User) role = 'user';\n else if (roleRaw === 'assistant' || roleRaw === AiAgentMessageRole.Assistant) role = 'assistant';\n else if (roleRaw === 'system') role = 'system';\n\n const rawContent = post?.message ?? '';\n const content = sanitizeAssistantContentByRole(role, rawContent);\n\n return {\n id: post?.id ?? uuidv4(),\n sessionId: post?.channel?.id ?? fallbackChannelId,\n role,\n content,\n attachments: (post?.files?.data ?? []).map((file) => ({\n id: file.id ?? uuidv4(),\n name: file.name ?? 'file',\n type: typeof file.mimeType === 'string' && file.mimeType.startsWith('image/') ? 'screenshot' : 'file',\n mimeType: file.mimeType ?? undefined,\n size: file.size ?? undefined,\n url: file.url ?? undefined,\n })),\n tokenCount: props.tokenCount ?? undefined,\n model: props.model ?? undefined,\n createdAt: post?.createdAt ? new Date(post.createdAt) : new Date(),\n updatedAt: post?.updatedAt ? new Date(post.updatedAt) : new Date(),\n };\n}\n\nexport function useChatMessages(sessionId: string | null, options?: { skip?: boolean }) {\n const { data, loading, error, refetch } = useMessagesQuery({\n variables: {\n channelId: sessionId ?? undefined,\n parentId: null,\n limit: MESSAGES_PAGE_LIMIT,\n skip: 0,\n },\n skip: !sessionId || options?.skip,\n fetchPolicy: 'cache-and-network',\n notifyOnNetworkStatusChange: true,\n /**\n * Cache key is per-channel so switching sessions doesn't read another channel's response.\n * Keeping this as a constant ('messages-list') used to cause cross-session bleed in the\n * custom Apollo link before reaching the normalized cache.\n */\n context: { cacheKey: sessionId ? `messages-list:${sessionId}` : 'messages-list' },\n });\n\n /**\n * `messagesLoaded` means \"we have data we can show\", regardless of whether a\n * background revalidation is in flight. With `cache-and-network`, Apollo\n * fills `data` from cache synchronously while `loading` is still true for\n * the network round-trip — gating hydration on `!loading` made every chat\n * revisit show a loader for the network latency even though the messages\n * were already cached. The chat stream re-hydrates whenever `data` changes,\n * so the fresh network response still swaps in silently afterward.\n */\n const messagesLoaded = data !== undefined;\n\n const messages: ChatMessageUI[] = useMemo(() => {\n if (!sessionId) return [];\n const rows = data?.messages?.data ?? [];\n return rows\n .map((post) => mapPostToChatMessageUI(post as MinimalPost, sessionId))\n .sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime());\n }, [data, sessionId]);\n\n return { messages, loading, messagesLoaded, error, refetch };\n}\n\nexport type IAccountSaveChatMessagesInput = IAccountSaveChatMessagesInputBase & {\n mode?: 'plan' | 'build';\n createdBy?: string;\n};\n\nexport function useChatMutations() {\n const [addChannelMutation, { loading: createChannelLoading }] = useAddChannelMutation();\n const [sendMessagesMutation, { loading: sendMessagesLoading }] = useSendMessagesMutation();\n\n const createChannel = useCallback(\n async (input?: IAccountCreateChatSessionInput): Promise<ChatSessionUI> => {\n const {\n orgName: orgNameArg,\n projectId: projectIdArg,\n ...inputForSettings\n } = (input ?? {}) as IAccountCreateChatSessionInput & {\n orgName?: string | null;\n projectId?: string | null;\n };\n const orgName =\n typeof orgNameArg === 'string' && orgNameArg.trim().length > 0 ? orgNameArg.trim() : undefined;\n const projectId =\n typeof projectIdArg === 'string' && projectIdArg.trim().length > 0 ? projectIdArg.trim() : undefined;\n\n const settings = {\n title: input?.title ?? 'New Chat',\n description: input?.systemPrompt ?? null,\n isShared: false,\n sharedSlug: null,\n isArchived: false,\n isPinned: false,\n model: input?.model ?? null,\n systemPrompt: input?.systemPrompt ?? null,\n ...inputForSettings,\n };\n\n const { data } = await addChannelMutation({\n variables: {\n channelId: input?.id ?? null,\n name: input?.title ?? 'New Chat',\n description: input?.systemPrompt ?? null,\n type: RoomType.Aiassistant,\n settings,\n ...(orgName ? { orgName } : {}),\n ...(projectId ? { projectId } : {}),\n },\n /**\n * Refetch every cache slot the rest of the app is watching for\n * channel lists. Apollo keys cached results by `variables`, so each\n * shape we emit here must match a watched query exactly.\n *\n * Variants:\n * 1. Legacy limit:100 list (web parity, no `criteria.orgName`).\n * 2. Mobile history-screen variant WITH `criteria.orgName` so the\n * resolver's `$in: [slug, orgId]` matches mobile-created channels.\n * 3. Same variant WITHOUT orgName, in case the screen mounted before\n * org settings resolved.\n */\n refetchQueries: [\n { query: GetChannelsByUserWithLastMessageDocument, variables: AI_ASSISTANT_CHANNELS_QUERY_VARS },\n ...(orgName\n ? [\n {\n query: GetChannelsByUserWithLastMessageDocument,\n variables: getHistoryChannelsQueryVariables(orgName),\n },\n ]\n : []),\n { query: GetChannelsByUserWithLastMessageDocument, variables: HISTORY_QUERY_BASE },\n ],\n awaitRefetchQueries: true,\n });\n\n if (!data?.createChannel?.id) {\n throw new Error('Failed to create channel');\n }\n\n const channel = data.createChannel;\n const title = channel.title ?? input?.title ?? 'New Chat';\n const now = new Date();\n\n return {\n id: channel.id,\n title,\n createdAt: now,\n updatedAt: now,\n };\n },\n [addChannelMutation],\n );\n\n const saveMessages = useCallback(\n async (\n input: IAccountSaveChatMessagesInput,\n ): Promise<{\n userMessage: ChatMessageUI;\n assistantMessage: ChatMessageUI;\n session: ChatSessionUI;\n }> => {\n const sanitizedAssistantContent = stripModelCostHeader(input.assistantMessage.content ?? '');\n const assistantMessageWithoutContent = omitContent((input.assistantMessage as any) ?? {});\n const userResult = await sendMessagesMutation({\n variables: {\n channelId: input.sessionId,\n type: RoomType.Aiassistant,\n content: input.userMessage.content ?? '',\n ...(input.createdBy ? { createdBy: input.createdBy } : {}),\n extraProps: {\n type: PostTypeEnum.Aiassistant,\n role: 'user',\n attachments: input.userMessage.attachments ?? [],\n isActive: true,\n status: 'complete',\n ...(input.userMessage as any),\n ...(input.mode ? { mode: input.mode } : {}),\n },\n } as any,\n });\n /**\n * Link the assistant reply to its prompting user message via `postId` (the parentId\n * on the schema). Without this, channel.lastMessage.propsConfiguration.contents.parent\n * stays null, the chat history can't recover the original prompt, and rows fall back\n * to the assistant reply as a label.\n */\n const userPostId = userResult.data?.sendMessage?.id ?? null;\n const assistantResult = await sendMessagesMutation({\n variables: {\n channelId: input.sessionId,\n type: RoomType.Aiassistant,\n content: sanitizedAssistantContent,\n ...(userPostId ? { postId: userPostId } : {}),\n extraProps: {\n type: PostTypeEnum.Aiassistant,\n role: 'assistant',\n attachments: input.assistantMessage.attachments ?? [],\n tokenCount: input.assistantMessage.tokenCount,\n latencyMs: input.assistantMessage.latencyMs,\n model: input.assistantMessage.model,\n finishReason: (input.assistantMessage as any).finishReason ?? null,\n isActive: true,\n status: 'complete',\n ...(userPostId ? { parentId: userPostId } : {}),\n ...assistantMessageWithoutContent,\n ...(input.mode ? { mode: input.mode } : {}),\n },\n } as any,\n });\n\n const userPost = userResult.data?.sendMessage;\n const assistantPost = assistantResult.data?.sendMessage;\n if (!userPost || !assistantPost) {\n throw new Error('Failed to send messages');\n }\n\n const now = new Date();\n return {\n userMessage: mapPostToChatMessageUI(userPost as MinimalPost, input.sessionId),\n assistantMessage: mapPostToChatMessageUI(assistantPost as MinimalPost, input.sessionId),\n session: {\n id: input.sessionId,\n title: 'Chat',\n createdAt: now,\n updatedAt: now,\n },\n };\n },\n [sendMessagesMutation],\n );\n\n return {\n createChannel,\n createSession: createChannel,\n saveMessages,\n loading: { create: createChannelLoading, saveMessages: sendMessagesLoading },\n };\n}\n"],"names":["uuidv4","_a","_b","_c","_d","_e"],"mappings":"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"}
|
|
@@ -1,4 +1,23 @@
|
|
|
1
|
-
import {useState,useRef,useCallback,useMemo,useEffect}from'react';import {useChatMutations,useChatMessages}from'./useChatApi.js';import {useCdecliChannel}from'./useCdecliChannel.js';import {streamChatResponse}from'../api/chatApi.js';
|
|
1
|
+
import {useState,useRef,useCallback,useMemo,useEffect}from'react';import {useChatMutations,useChatMessages}from'./useChatApi.js';import {useCdecliChannel}from'./useCdecliChannel.js';import {usePrerequisiteIds}from'./usePrerequisiteIds.js';import {streamChatResponse}from'../api/chatApi.js';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
|
+
const REVEAL_CHUNK_SIZE = 6;
|
|
2
21
|
const REVEAL_INTERVAL_MS = 20;
|
|
3
22
|
function isCdecliAgentFailureOutput(text) {
|
|
4
23
|
const t = text.trim();
|
|
@@ -27,8 +46,14 @@ function useChatStream(sessionId, routing = {
|
|
|
27
46
|
saveMessages
|
|
28
47
|
} = useChatMutations();
|
|
29
48
|
const {
|
|
30
|
-
|
|
49
|
+
accountUserId
|
|
50
|
+
} = usePrerequisiteIds();
|
|
51
|
+
const {
|
|
52
|
+
messages: backendMessages,
|
|
53
|
+
loading: backendMessagesLoading,
|
|
54
|
+
messagesLoaded: backendMessagesLoaded
|
|
31
55
|
} = useChatMessages(sessionId);
|
|
56
|
+
const lastHydratedSessionIdRef = useRef(null);
|
|
32
57
|
const executeGroqStream = useCallback(async (conv, effectiveSessionId, userMessage) => {
|
|
33
58
|
var _a, _b;
|
|
34
59
|
abortRef.current = new AbortController();
|
|
@@ -74,8 +99,11 @@ function useChatStream(sessionId, routing = {
|
|
|
74
99
|
setMessages((prev) => [...prev, assistantMessage2]);
|
|
75
100
|
setResponse("");
|
|
76
101
|
if (effectiveSessionId) {
|
|
77
|
-
saveMessages({
|
|
78
|
-
sessionId: effectiveSessionId
|
|
102
|
+
saveMessages(__spreadProps(__spreadValues({
|
|
103
|
+
sessionId: effectiveSessionId
|
|
104
|
+
}, accountUserId ? {
|
|
105
|
+
createdBy: accountUserId
|
|
106
|
+
} : {}), {
|
|
79
107
|
userMessage: {
|
|
80
108
|
content: userMessage.content,
|
|
81
109
|
attachments: (_a2 = userMessage.attachments) == null ? void 0 : _a2.map((a) => ({
|
|
@@ -92,7 +120,7 @@ function useChatStream(sessionId, routing = {
|
|
|
92
120
|
tokenCount: (_b2 = result.tokenUsage) == null ? void 0 : _b2.totalTokens,
|
|
93
121
|
model: void 0
|
|
94
122
|
}
|
|
95
|
-
}).catch((e) => console.error("[useChatStream] saveMessages (fallback):", e));
|
|
123
|
+
})).catch((e) => console.error("[useChatStream] saveMessages (fallback):", e));
|
|
96
124
|
}
|
|
97
125
|
isSendingRef.current = false;
|
|
98
126
|
setIsLoading(false);
|
|
@@ -118,8 +146,11 @@ function useChatStream(sessionId, routing = {
|
|
|
118
146
|
setMessages((prev) => [...prev, assistantMessage]);
|
|
119
147
|
setResponse("");
|
|
120
148
|
if (effectiveSessionId) {
|
|
121
|
-
await saveMessages({
|
|
122
|
-
sessionId: effectiveSessionId
|
|
149
|
+
await saveMessages(__spreadProps(__spreadValues({
|
|
150
|
+
sessionId: effectiveSessionId
|
|
151
|
+
}, accountUserId ? {
|
|
152
|
+
createdBy: accountUserId
|
|
153
|
+
} : {}), {
|
|
123
154
|
userMessage: {
|
|
124
155
|
content: userMessage.content,
|
|
125
156
|
attachments: (_a = userMessage.attachments) == null ? void 0 : _a.map((a) => ({
|
|
@@ -136,7 +167,7 @@ function useChatStream(sessionId, routing = {
|
|
|
136
167
|
tokenCount: (_b = result.tokenUsage) == null ? void 0 : _b.totalTokens,
|
|
137
168
|
model: void 0
|
|
138
169
|
}
|
|
139
|
-
});
|
|
170
|
+
}));
|
|
140
171
|
}
|
|
141
172
|
} catch (err) {
|
|
142
173
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -152,7 +183,7 @@ function useChatStream(sessionId, routing = {
|
|
|
152
183
|
saveSessionIdRef.current = null;
|
|
153
184
|
}
|
|
154
185
|
}
|
|
155
|
-
}, [saveMessages]);
|
|
186
|
+
}, [saveMessages, accountUserId]);
|
|
156
187
|
const streamChannelId = sessionId || cdecliStreamOverrideId;
|
|
157
188
|
const isCdecliActive = routing.kind === "cdecli" && routing.channelConnected;
|
|
158
189
|
const cdecliCallbacks = useMemo(() => ({
|
|
@@ -210,8 +241,11 @@ function useChatStream(sessionId, routing = {
|
|
|
210
241
|
const rt = routingRef.current;
|
|
211
242
|
const persistClientSide = rt.kind === "cdecli" && rt.persistenceMode !== "backend";
|
|
212
243
|
if (sid && um && persistClientSide) {
|
|
213
|
-
void saveMessages({
|
|
214
|
-
sessionId: sid
|
|
244
|
+
void saveMessages(__spreadProps(__spreadValues({
|
|
245
|
+
sessionId: sid
|
|
246
|
+
}, accountUserId ? {
|
|
247
|
+
createdBy: accountUserId
|
|
248
|
+
} : {}), {
|
|
215
249
|
userMessage: {
|
|
216
250
|
content: um.content,
|
|
217
251
|
attachments: (_a = um.attachments) == null ? void 0 : _a.map((a) => ({
|
|
@@ -228,7 +262,7 @@ function useChatStream(sessionId, routing = {
|
|
|
228
262
|
tokenCount: void 0,
|
|
229
263
|
model: "cdecli-serve"
|
|
230
264
|
}
|
|
231
|
-
}).catch((e) => console.error("[useChatStream] saveMessages (cdecli):", e));
|
|
265
|
+
})).catch((e) => console.error("[useChatStream] saveMessages (cdecli):", e));
|
|
232
266
|
}
|
|
233
267
|
},
|
|
234
268
|
onError: (err) => {
|
|
@@ -259,7 +293,7 @@ function useChatStream(sessionId, routing = {
|
|
|
259
293
|
userMsgForSaveRef.current = null;
|
|
260
294
|
saveSessionIdRef.current = null;
|
|
261
295
|
}
|
|
262
|
-
}), [saveMessages, executeGroqStream]);
|
|
296
|
+
}), [saveMessages, executeGroqStream, accountUserId]);
|
|
263
297
|
const {
|
|
264
298
|
sendMessage: sendCdecliMessage
|
|
265
299
|
} = useCdecliChannel(routing.kind === "cdecli", isCdecliActive, routing.kind === "cdecli" ? routing.accountId : "default", streamChannelId, cdecliCallbacks);
|
|
@@ -279,10 +313,17 @@ function useChatStream(sessionId, routing = {
|
|
|
279
313
|
if (!sessionId) {
|
|
280
314
|
setMessages([]);
|
|
281
315
|
setResponse("");
|
|
316
|
+
lastHydratedSessionIdRef.current = null;
|
|
282
317
|
return;
|
|
283
318
|
}
|
|
284
|
-
|
|
285
|
-
|
|
319
|
+
const sessionChanged = lastHydratedSessionIdRef.current !== sessionId;
|
|
320
|
+
if (sessionChanged) {
|
|
321
|
+
setMessages([]);
|
|
322
|
+
setResponse("");
|
|
323
|
+
lastHydratedSessionIdRef.current = sessionId;
|
|
324
|
+
}
|
|
325
|
+
if (backendMessagesLoaded) {
|
|
326
|
+
const formatted = (backendMessages != null ? backendMessages : []).map((msg) => {
|
|
286
327
|
var _a;
|
|
287
328
|
return {
|
|
288
329
|
role: msg.role,
|
|
@@ -300,7 +341,7 @@ function useChatStream(sessionId, routing = {
|
|
|
300
341
|
setMessages(formatted);
|
|
301
342
|
setResponse("");
|
|
302
343
|
}
|
|
303
|
-
}, [sessionId, backendMessages]);
|
|
344
|
+
}, [sessionId, backendMessages, backendMessagesLoaded]);
|
|
304
345
|
const sendMessage = useCallback(async (content, attachments, sessionIdOverride) => {
|
|
305
346
|
if (!content.trim()) return;
|
|
306
347
|
const effectiveSessionId = sessionIdOverride !== void 0 ? sessionIdOverride : sessionId;
|
|
@@ -369,12 +410,14 @@ function useChatStream(sessionId, routing = {
|
|
|
369
410
|
setResponse("");
|
|
370
411
|
setError(null);
|
|
371
412
|
}, []);
|
|
413
|
+
const messagesLoading = !!sessionId && backendMessagesLoading && !backendMessagesLoaded;
|
|
372
414
|
return {
|
|
373
415
|
messages,
|
|
374
416
|
response,
|
|
375
417
|
error,
|
|
376
418
|
isLoading,
|
|
377
419
|
isStreaming,
|
|
420
|
+
messagesLoading,
|
|
378
421
|
hasMessages: messages.length > 0 || !!response,
|
|
379
422
|
sendMessage,
|
|
380
423
|
cancel,
|