@adminide-stack/yantra-mobile 12.0.28-alpha.51 → 12.0.28-alpha.58

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/lib/assets/icon.png +0 -0
  2. package/lib/components/CustomDrawer.js +358 -0
  3. package/lib/components/CustomDrawer.js.map +1 -0
  4. package/lib/components/GatewayToolbarButtonMobile.js +84 -0
  5. package/lib/components/GatewayToolbarButtonMobile.js.map +1 -0
  6. package/lib/components/YantraBrandLoader.js +94 -0
  7. package/lib/components/YantraBrandLoader.js.map +1 -0
  8. package/lib/compute.js +37 -5
  9. package/lib/compute.js.map +1 -1
  10. package/lib/config/constants.js +16 -0
  11. package/lib/config/constants.js.map +1 -0
  12. package/lib/config/env-config.js +74 -19
  13. package/lib/config/env-config.js.map +1 -1
  14. package/lib/contexts/GatewayContext.js +77 -0
  15. package/lib/contexts/GatewayContext.js.map +1 -0
  16. package/lib/graphql/agentGatewayDocuments.js +53 -0
  17. package/lib/graphql/agentGatewayDocuments.js.map +1 -0
  18. package/lib/hooks/useCdecliAutoConnect.js +219 -0
  19. package/lib/hooks/useCdecliAutoConnect.js.map +1 -0
  20. package/lib/hooks/useCdecliChannel.js +226 -0
  21. package/lib/hooks/useCdecliChannel.js.map +1 -0
  22. package/lib/hooks/useChatApi.js +220 -170
  23. package/lib/hooks/useChatApi.js.map +1 -1
  24. package/lib/hooks/useChatStream.js +232 -58
  25. package/lib/hooks/useChatStream.js.map +1 -1
  26. package/lib/hooks/useGatewayConnection.js +123 -0
  27. package/lib/hooks/useGatewayConnection.js.map +1 -0
  28. package/lib/hooks/useGatewayRegistry.js +28 -0
  29. package/lib/hooks/useGatewayRegistry.js.map +1 -0
  30. package/lib/hooks/usePrerequisiteIds.js +122 -0
  31. package/lib/hooks/usePrerequisiteIds.js.map +1 -0
  32. package/lib/hooks/useWorkspaceProvisioner.js +236 -0
  33. package/lib/hooks/useWorkspaceProvisioner.js.map +1 -0
  34. package/lib/index.js +1 -1
  35. package/lib/index.js.map +1 -1
  36. package/lib/routes.json +8 -5
  37. package/lib/screens/Home/HomeScreen.js +420 -97
  38. package/lib/screens/Home/HomeScreen.js.map +1 -1
  39. package/lib/screens/Home/components/ChatHistoryLanding.js +229 -0
  40. package/lib/screens/Home/components/ChatHistoryLanding.js.map +1 -0
  41. package/lib/screens/Home/components/DeepSearchModal.js +334 -0
  42. package/lib/screens/Home/components/DeepSearchModal.js.map +1 -0
  43. package/lib/screens/Home/deepSearchUtils.js +41 -0
  44. package/lib/screens/Home/deepSearchUtils.js.map +1 -0
  45. package/lib/screens/NewChat/index.js +75 -0
  46. package/lib/screens/NewChat/index.js.map +1 -0
  47. package/lib/services/agentSessionManager.js +451 -0
  48. package/lib/services/agentSessionManager.js.map +1 -0
  49. package/lib/services/gatewayApiKeyBridge.js +4 -0
  50. package/lib/services/gatewayApiKeyBridge.js.map +1 -0
  51. package/lib/services/gatewayClient.js +470 -0
  52. package/lib/services/gatewayClient.js.map +1 -0
  53. package/lib/utils/gatewaySelectionStorage.js +21 -0
  54. package/lib/utils/gatewaySelectionStorage.js.map +1 -0
  55. package/package.json +7 -3
@@ -1,6 +1,13 @@
1
- import {useState,useRef,useEffect,useCallback}from'react';import {useChatMutations,useChatMessages}from'./useChatApi.js';import {streamChatResponse}from'../api/chatApi.js';const REVEAL_CHUNK_SIZE = 6;
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';const REVEAL_CHUNK_SIZE = 6;
2
2
  const REVEAL_INTERVAL_MS = 20;
3
- function useChatStream(sessionId) {
3
+ function isCdecliAgentFailureOutput(text) {
4
+ const t = text.trim();
5
+ if (!t) return false;
6
+ return /⚠\s*Error:/.test(t) || /LLM stream error/i.test(t) || /Incorrect API key/i.test(t) || /invalid_api_key/i.test(t) || /authentication_error/i.test(t);
7
+ }
8
+ function useChatStream(sessionId, routing = {
9
+ kind: "groq"
10
+ }) {
4
11
  const [messages, setMessages] = useState([]);
5
12
  const [response, setResponse] = useState("");
6
13
  const [isLoading, setIsLoading] = useState(false);
@@ -9,68 +16,26 @@ function useChatStream(sessionId) {
9
16
  const abortRef = useRef(null);
10
17
  const isSendingRef = useRef(false);
11
18
  const revealIntervalRef = useRef(null);
19
+ const [cdecliStreamOverrideId, setCdecliStreamOverrideId] = useState(void 0);
20
+ const userMsgForSaveRef = useRef(null);
21
+ const saveSessionIdRef = useRef(null);
22
+ const cdecliRoundHandledRef = useRef(false);
23
+ const cdecliFallbackConversationRef = useRef(null);
24
+ const routingRef = useRef(routing);
25
+ routingRef.current = routing;
12
26
  const {
13
27
  saveMessages
14
28
  } = useChatMutations();
15
29
  const {
16
30
  messages: backendMessages
17
31
  } = useChatMessages(sessionId);
18
- useEffect(() => () => {
19
- if (revealIntervalRef.current) {
20
- clearInterval(revealIntervalRef.current);
21
- revealIntervalRef.current = null;
22
- }
23
- }, []);
24
- useEffect(() => {
25
- if (isSendingRef.current) return;
26
- if (!sessionId) {
27
- setMessages([]);
28
- setResponse("");
29
- return;
30
- }
31
- if (backendMessages && backendMessages.length > 0) {
32
- const formatted = backendMessages.map((msg) => {
33
- var _a;
34
- return {
35
- role: msg.role,
36
- content: (_a = msg.content) != null ? _a : "",
37
- metadata: msg.tokenCount ? {
38
- tokenUsage: {
39
- inputTokens: 0,
40
- outputTokens: msg.tokenCount,
41
- totalTokens: msg.tokenCount
42
- },
43
- model: msg.model
44
- } : void 0
45
- };
46
- });
47
- setMessages(formatted);
48
- setResponse("");
49
- }
50
- }, [sessionId, backendMessages]);
51
- const sendMessage = useCallback(async (content, attachments, sessionIdOverride) => {
32
+ const executeGroqStream = useCallback(async (conv, effectiveSessionId, userMessage) => {
52
33
  var _a, _b;
53
- if (!content.trim()) return;
54
- const effectiveSessionId = sessionIdOverride !== void 0 ? sessionIdOverride : sessionId;
55
- const userMessage = {
56
- role: "user",
57
- content: content.trim(),
58
- attachments
59
- };
60
- isSendingRef.current = true;
61
- setMessages((prev) => [...prev, userMessage]);
62
- setResponse("");
63
- setIsLoading(true);
64
- setIsStreaming(true);
65
- setError(null);
66
34
  abortRef.current = new AbortController();
67
- const chatMessages = [...messages.map((m) => ({
35
+ const chatMessages = conv.map((m) => ({
68
36
  role: m.role,
69
37
  content: m.content
70
- })), {
71
- role: "user",
72
- content: content.trim()
73
- }];
38
+ }));
74
39
  let doingChunkedReveal = false;
75
40
  try {
76
41
  const g = global;
@@ -127,12 +92,14 @@ function useChatStream(sessionId) {
127
92
  tokenCount: (_b2 = result.tokenUsage) == null ? void 0 : _b2.totalTokens,
128
93
  model: void 0
129
94
  }
130
- }).catch((e) => console.error("[useChatStream] saveMessages:", e));
95
+ }).catch((e) => console.error("[useChatStream] saveMessages (fallback):", e));
131
96
  }
132
97
  isSendingRef.current = false;
133
98
  setIsLoading(false);
134
99
  setIsStreaming(false);
135
100
  abortRef.current = null;
101
+ userMsgForSaveRef.current = null;
102
+ saveSessionIdRef.current = null;
136
103
  }
137
104
  }, REVEAL_INTERVAL_MS);
138
105
  return;
@@ -173,8 +140,7 @@ function useChatStream(sessionId) {
173
140
  }
174
141
  } catch (err) {
175
142
  const msg = err instanceof Error ? err.message : String(err);
176
- if (msg.includes("abort")) return;
177
- setError(msg);
143
+ if (!msg.includes("abort")) setError(msg);
178
144
  setResponse("");
179
145
  } finally {
180
146
  if (!doingChunkedReveal) {
@@ -182,9 +148,217 @@ function useChatStream(sessionId) {
182
148
  setIsLoading(false);
183
149
  setIsStreaming(false);
184
150
  abortRef.current = null;
151
+ userMsgForSaveRef.current = null;
152
+ saveSessionIdRef.current = null;
185
153
  }
186
154
  }
187
- }, [messages, sessionId, saveMessages]);
155
+ }, [saveMessages]);
156
+ const streamChannelId = sessionId || cdecliStreamOverrideId;
157
+ const isCdecliActive = routing.kind === "cdecli" && routing.channelConnected;
158
+ const cdecliCallbacks = useMemo(() => ({
159
+ onChunk: (text) => {
160
+ if (routingRef.current.kind !== "cdecli") return;
161
+ setResponse((r) => r + text);
162
+ },
163
+ onComplete: (text) => {
164
+ var _a;
165
+ if (routingRef.current.kind !== "cdecli") return;
166
+ if (cdecliRoundHandledRef.current) {
167
+ return;
168
+ }
169
+ if (isCdecliAgentFailureOutput(text)) {
170
+ cdecliRoundHandledRef.current = true;
171
+ console.warn("[useChatStream] CDeCLI agent error output; retrying via direct chat API");
172
+ const sid2 = saveSessionIdRef.current;
173
+ const um2 = userMsgForSaveRef.current;
174
+ const conv = cdecliFallbackConversationRef.current;
175
+ setResponse("");
176
+ setError(null);
177
+ userMsgForSaveRef.current = um2;
178
+ saveSessionIdRef.current = sid2;
179
+ setIsLoading(true);
180
+ setIsStreaming(true);
181
+ isSendingRef.current = true;
182
+ if ((conv == null ? void 0 : conv.length) && um2) {
183
+ void executeGroqStream(conv, sid2, um2);
184
+ return;
185
+ }
186
+ setMessages((prev) => [...prev, {
187
+ role: "assistant",
188
+ content: text
189
+ }]);
190
+ setIsLoading(false);
191
+ setIsStreaming(false);
192
+ isSendingRef.current = false;
193
+ userMsgForSaveRef.current = null;
194
+ saveSessionIdRef.current = null;
195
+ return;
196
+ }
197
+ cdecliRoundHandledRef.current = true;
198
+ const sid = saveSessionIdRef.current;
199
+ const um = userMsgForSaveRef.current;
200
+ saveSessionIdRef.current = null;
201
+ userMsgForSaveRef.current = null;
202
+ setMessages((prev) => [...prev, {
203
+ role: "assistant",
204
+ content: text
205
+ }]);
206
+ setResponse("");
207
+ setIsLoading(false);
208
+ setIsStreaming(false);
209
+ isSendingRef.current = false;
210
+ const rt = routingRef.current;
211
+ const persistClientSide = rt.kind === "cdecli" && rt.persistenceMode !== "backend";
212
+ if (sid && um && persistClientSide) {
213
+ void saveMessages({
214
+ sessionId: sid,
215
+ userMessage: {
216
+ content: um.content,
217
+ attachments: (_a = um.attachments) == null ? void 0 : _a.map((a) => ({
218
+ id: a.id,
219
+ name: a.name,
220
+ type: a.type,
221
+ mimeType: a.mimeType,
222
+ size: a.size,
223
+ url: a.url
224
+ }))
225
+ },
226
+ assistantMessage: {
227
+ content: text,
228
+ tokenCount: void 0,
229
+ model: "cdecli-serve"
230
+ }
231
+ }).catch((e) => console.error("[useChatStream] saveMessages (cdecli):", e));
232
+ }
233
+ },
234
+ onError: (err) => {
235
+ if (routingRef.current.kind !== "cdecli") return;
236
+ if (cdecliRoundHandledRef.current) return;
237
+ const conv = cdecliFallbackConversationRef.current;
238
+ const um = userMsgForSaveRef.current;
239
+ const sid = saveSessionIdRef.current;
240
+ if ((conv == null ? void 0 : conv.length) && um) {
241
+ cdecliRoundHandledRef.current = true;
242
+ console.warn("[useChatStream] CDeCLI transport/stream error; falling back to direct chat API:", err);
243
+ setResponse("");
244
+ setError(null);
245
+ userMsgForSaveRef.current = um;
246
+ saveSessionIdRef.current = sid;
247
+ setIsLoading(true);
248
+ setIsStreaming(true);
249
+ isSendingRef.current = true;
250
+ void executeGroqStream(conv, sid, um);
251
+ return;
252
+ }
253
+ cdecliRoundHandledRef.current = false;
254
+ setError(err);
255
+ setResponse("");
256
+ setIsLoading(false);
257
+ setIsStreaming(false);
258
+ isSendingRef.current = false;
259
+ userMsgForSaveRef.current = null;
260
+ saveSessionIdRef.current = null;
261
+ }
262
+ }), [saveMessages, executeGroqStream]);
263
+ const {
264
+ sendMessage: sendCdecliMessage
265
+ } = useCdecliChannel(routing.kind === "cdecli", isCdecliActive, routing.kind === "cdecli" ? routing.accountId : "default", streamChannelId, cdecliCallbacks);
266
+ useEffect(() => () => {
267
+ if (revealIntervalRef.current) {
268
+ clearInterval(revealIntervalRef.current);
269
+ revealIntervalRef.current = null;
270
+ }
271
+ }, []);
272
+ useEffect(() => {
273
+ if (sessionId && cdecliStreamOverrideId && sessionId === cdecliStreamOverrideId) {
274
+ setCdecliStreamOverrideId(void 0);
275
+ }
276
+ }, [sessionId, cdecliStreamOverrideId]);
277
+ useEffect(() => {
278
+ if (isSendingRef.current) return;
279
+ if (!sessionId) {
280
+ setMessages([]);
281
+ setResponse("");
282
+ return;
283
+ }
284
+ if (backendMessages && backendMessages.length > 0) {
285
+ const formatted = backendMessages.map((msg) => {
286
+ var _a;
287
+ return {
288
+ role: msg.role,
289
+ content: (_a = msg.content) != null ? _a : "",
290
+ metadata: msg.tokenCount ? {
291
+ tokenUsage: {
292
+ inputTokens: 0,
293
+ outputTokens: msg.tokenCount,
294
+ totalTokens: msg.tokenCount
295
+ },
296
+ model: msg.model
297
+ } : void 0
298
+ };
299
+ });
300
+ setMessages(formatted);
301
+ setResponse("");
302
+ }
303
+ }, [sessionId, backendMessages]);
304
+ const sendMessage = useCallback(async (content, attachments, sessionIdOverride) => {
305
+ if (!content.trim()) return;
306
+ const effectiveSessionId = sessionIdOverride !== void 0 ? sessionIdOverride : sessionId;
307
+ const userMessage = {
308
+ role: "user",
309
+ content: content.trim(),
310
+ attachments
311
+ };
312
+ isSendingRef.current = true;
313
+ setMessages((prev) => [...prev, userMessage]);
314
+ setResponse("");
315
+ setIsLoading(true);
316
+ setIsStreaming(true);
317
+ setError(null);
318
+ userMsgForSaveRef.current = userMessage;
319
+ saveSessionIdRef.current = effectiveSessionId != null ? effectiveSessionId : null;
320
+ cdecliRoundHandledRef.current = false;
321
+ const rt = routingRef.current;
322
+ if (rt.kind === "cdecli") {
323
+ if (!rt.channelConnected) {
324
+ setError("CDeCLI is not connected yet. Check gateway status in the header.");
325
+ setMessages((p) => p.slice(0, -1));
326
+ isSendingRef.current = false;
327
+ setIsLoading(false);
328
+ setIsStreaming(false);
329
+ userMsgForSaveRef.current = null;
330
+ saveSessionIdRef.current = null;
331
+ return;
332
+ }
333
+ if (!effectiveSessionId) {
334
+ setError("Missing chat session id.");
335
+ setMessages((p) => p.slice(0, -1));
336
+ isSendingRef.current = false;
337
+ setIsLoading(false);
338
+ setIsStreaming(false);
339
+ userMsgForSaveRef.current = null;
340
+ saveSessionIdRef.current = null;
341
+ return;
342
+ }
343
+ if (sessionIdOverride) {
344
+ setCdecliStreamOverrideId(sessionIdOverride);
345
+ await new Promise((r) => setTimeout(r, 0));
346
+ }
347
+ cdecliFallbackConversationRef.current = [...messages, userMessage];
348
+ const ok = await sendCdecliMessage(content.trim(), effectiveSessionId);
349
+ if (!ok && !cdecliRoundHandledRef.current) {
350
+ const conv = cdecliFallbackConversationRef.current;
351
+ console.warn("[useChatStream] CDeCLI send returned false; falling back to direct chat API");
352
+ cdecliRoundHandledRef.current = true;
353
+ userMsgForSaveRef.current = userMessage;
354
+ saveSessionIdRef.current = effectiveSessionId != null ? effectiveSessionId : null;
355
+ void executeGroqStream(conv != null ? conv : [], effectiveSessionId != null ? effectiveSessionId : null, userMessage);
356
+ return;
357
+ }
358
+ return;
359
+ }
360
+ await executeGroqStream([...messages, userMessage], effectiveSessionId != null ? effectiveSessionId : null, userMessage);
361
+ }, [messages, sessionId, sendCdecliMessage, executeGroqStream]);
188
362
  const cancel = useCallback(() => {
189
363
  if (abortRef.current) {
190
364
  abortRef.current.abort();
@@ -1 +1 @@
1
- {"version":3,"file":"useChatStream.js","sources":["../../src/hooks/useChatStream.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\nimport { useChatMutations, useChatMessages } from './useChatApi';\nimport { streamChatResponse } from '../api/chatApi';\n\n/** Chunk size for simulated streaming reveal (Kimi-style step-by-step) */\nconst REVEAL_CHUNK_SIZE = 6;\n/** Delay in ms between chunks */\nconst REVEAL_INTERVAL_MS = 20;\n\nexport interface MessageAttachment {\n id: string;\n name: string;\n type: 'file' | 'screenshot';\n dataUrl?: string;\n mimeType?: string;\n size?: number;\n url?: string;\n}\n\nexport interface ChatMessage {\n role: 'user' | 'assistant';\n content: string;\n attachments?: MessageAttachment[];\n metadata?: {\n tokenUsage?: { inputTokens: number; outputTokens: number; totalTokens: number };\n model?: string;\n };\n}\n\nexport function useChatStream(sessionId: string | null) {\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [response, setResponse] = useState('');\n const [isLoading, setIsLoading] = useState(false);\n const [isStreaming, setIsStreaming] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n const isSendingRef = useRef(false);\n const revealIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n const { saveMessages } = useChatMutations();\n const { messages: backendMessages } = useChatMessages(sessionId);\n\n useEffect(\n () => () => {\n if (revealIntervalRef.current) {\n clearInterval(revealIntervalRef.current);\n revealIntervalRef.current = null;\n }\n },\n [],\n );\n\n // Load messages from backend when session changes (skip if we're actively sending)\n useEffect(() => {\n if (isSendingRef.current) return;\n\n if (!sessionId) {\n setMessages([]);\n setResponse('');\n return;\n }\n // Only sync from backend when we have data - never clear when backend is empty\n // (we may have local messages from a send that just completed)\n if (backendMessages && backendMessages.length > 0) {\n const formatted: ChatMessage[] = backendMessages.map((msg) => ({\n role: msg.role as 'user' | 'assistant',\n content: msg.content ?? '',\n metadata: msg.tokenCount\n ? {\n tokenUsage: {\n inputTokens: 0,\n outputTokens: msg.tokenCount,\n totalTokens: msg.tokenCount,\n },\n model: msg.model,\n }\n : undefined,\n }));\n setMessages(formatted);\n setResponse('');\n }\n }, [sessionId, backendMessages]);\n\n const sendMessage = useCallback(\n async (content: string, attachments?: MessageAttachment[], sessionIdOverride?: string | null) => {\n if (!content.trim()) return;\n\n const effectiveSessionId = sessionIdOverride !== undefined ? sessionIdOverride : sessionId;\n\n const userMessage: ChatMessage = {\n role: 'user',\n content: content.trim(),\n attachments,\n };\n\n isSendingRef.current = true;\n setMessages((prev) => [...prev, userMessage]);\n setResponse('');\n setIsLoading(true);\n setIsStreaming(true);\n setError(null);\n\n abortRef.current = new AbortController();\n\n const chatMessages = [\n ...messages.map((m) => ({ role: m.role, content: m.content })),\n { role: 'user' as const, content: content.trim() },\n ];\n\n let doingChunkedReveal = false;\n try {\n const g = global as Record<string, unknown>;\n const preferNonStreaming =\n typeof g?.nativeCallSyncHook === 'function' || typeof g?.__fbBatchedBridge !== 'undefined';\n const result = await streamChatResponse(chatMessages, undefined, abortRef.current.signal, {\n preferNonStreaming,\n });\n const fullContent = result.content;\n\n if (preferNonStreaming && fullContent.length > 0) {\n doingChunkedReveal = true;\n if (revealIntervalRef.current) {\n clearInterval(revealIntervalRef.current);\n revealIntervalRef.current = null;\n }\n let revealedLen = 0;\n revealIntervalRef.current = setInterval(() => {\n revealedLen = Math.min(revealedLen + REVEAL_CHUNK_SIZE, fullContent.length);\n setResponse(fullContent.slice(0, revealedLen));\n if (revealedLen >= fullContent.length) {\n if (revealIntervalRef.current) {\n clearInterval(revealIntervalRef.current);\n revealIntervalRef.current = null;\n }\n const assistantMessage: ChatMessage = {\n role: 'assistant',\n content: fullContent,\n metadata: result.tokenUsage\n ? {\n tokenUsage: {\n inputTokens: result.tokenUsage.inputTokens,\n outputTokens: result.tokenUsage.outputTokens,\n totalTokens: result.tokenUsage.totalTokens,\n },\n }\n : undefined,\n };\n setMessages((prev) => [...prev, assistantMessage]);\n setResponse('');\n if (effectiveSessionId) {\n saveMessages({\n sessionId: effectiveSessionId,\n userMessage: {\n content: userMessage.content,\n attachments: userMessage.attachments?.map((a) => ({\n id: a.id,\n name: a.name,\n type: a.type,\n mimeType: a.mimeType,\n size: a.size,\n url: a.url,\n })),\n },\n assistantMessage: {\n content: fullContent,\n tokenCount: result.tokenUsage?.totalTokens,\n model: undefined,\n },\n }).catch((e) => console.error('[useChatStream] saveMessages:', e));\n }\n isSendingRef.current = false;\n setIsLoading(false);\n setIsStreaming(false);\n abortRef.current = null;\n }\n }, REVEAL_INTERVAL_MS);\n return;\n }\n\n const assistantMessage: ChatMessage = {\n role: 'assistant',\n content: fullContent,\n metadata: result.tokenUsage\n ? {\n tokenUsage: {\n inputTokens: result.tokenUsage.inputTokens,\n outputTokens: result.tokenUsage.outputTokens,\n totalTokens: result.tokenUsage.totalTokens,\n },\n }\n : undefined,\n };\n\n setMessages((prev) => [...prev, assistantMessage]);\n setResponse('');\n\n if (effectiveSessionId) {\n await saveMessages({\n sessionId: effectiveSessionId,\n userMessage: {\n content: userMessage.content,\n attachments: userMessage.attachments?.map((a) => ({\n id: a.id,\n name: a.name,\n type: a.type,\n mimeType: a.mimeType,\n size: a.size,\n url: a.url,\n })),\n },\n assistantMessage: {\n content: fullContent,\n tokenCount: result.tokenUsage?.totalTokens,\n model: undefined,\n },\n });\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (msg.includes('abort')) return;\n setError(msg);\n setResponse('');\n } finally {\n if (!doingChunkedReveal) {\n isSendingRef.current = false;\n setIsLoading(false);\n setIsStreaming(false);\n abortRef.current = null;\n }\n }\n },\n [messages, sessionId, saveMessages],\n );\n\n const cancel = useCallback(() => {\n if (abortRef.current) {\n abortRef.current.abort();\n }\n }, []);\n\n const clearMessages = useCallback(() => {\n setMessages([]);\n setResponse('');\n setError(null);\n }, []);\n\n return {\n messages,\n response,\n error,\n isLoading,\n isStreaming,\n hasMessages: messages.length > 0 || !!response,\n sendMessage,\n cancel,\n clearMessages,\n };\n}\n"],"names":["_a","_b","assistantMessage"],"mappings":"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"}
1
+ {"version":3,"file":"useChatStream.js","sources":["../../src/hooks/useChatStream.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { useChatMutations, useChatMessages } from './useChatApi';\nimport { useCdecliChannel } from './useCdecliChannel';\nimport { streamChatResponse } from '../api/chatApi';\n\nconst REVEAL_CHUNK_SIZE = 6;\nconst REVEAL_INTERVAL_MS = 20;\n\n/** Agent returned an error while the cdecli-serve channel stayed connected (e.g. bad LLM API key). */\nfunction isCdecliAgentFailureOutput(text: string): boolean {\n const t = text.trim();\n if (!t) return false;\n return (\n /⚠\\s*Error:/.test(t) ||\n /LLM stream error/i.test(t) ||\n /Incorrect API key/i.test(t) ||\n /invalid_api_key/i.test(t) ||\n /authentication_error/i.test(t)\n );\n}\n\nexport interface MessageAttachment {\n id: string;\n name: string;\n type: 'file' | 'screenshot';\n dataUrl?: string;\n mimeType?: string;\n size?: number;\n url?: string;\n}\n\nexport interface ChatMessage {\n role: 'user' | 'assistant';\n content: string;\n attachments?: MessageAttachment[];\n metadata?: {\n tokenUsage?: { inputTokens: number; outputTokens: number; totalTokens: number };\n model?: string;\n };\n}\n\n/** When `kind` is `cdecli`, messages go through messenger-gateway (same as web CDeCLI). */\nexport type UseChatStreamRouting =\n | { kind: 'groq' }\n | {\n kind: 'cdecli';\n channelConnected: boolean;\n accountId: string;\n /** From `gatewayConnect` / gateway registry — when `'backend'`, server persists; skip client `saveMessages`. */\n persistenceMode?: 'backend' | 'frontend';\n };\n\nexport function useChatStream(sessionId: string | null, routing: UseChatStreamRouting = { kind: 'groq' }) {\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [response, setResponse] = useState('');\n const [isLoading, setIsLoading] = useState(false);\n const [isStreaming, setIsStreaming] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const abortRef = useRef<AbortController | null>(null);\n const isSendingRef = useRef(false);\n const revealIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n /** Ensures GraphQL stream subscriptions use the id from createChannel+send before the next parent render. */\n const [cdecliStreamOverrideId, setCdecliStreamOverrideId] = useState<string | undefined>(undefined);\n const userMsgForSaveRef = useRef<ChatMessage | null>(null);\n const saveSessionIdRef = useRef<string | null>(null);\n /** Blocks duplicate cdecli `onComplete` from appending assistant twice / saving twice per send. */\n const cdecliRoundHandledRef = useRef(false);\n /** Snapshot of `[...priorMessages, userMessage]` for Groq fallback when CDeCLI send/stream fails. */\n const cdecliFallbackConversationRef = useRef<ChatMessage[] | null>(null);\n const routingRef = useRef(routing);\n routingRef.current = routing;\n\n const { saveMessages } = useChatMutations();\n const { messages: backendMessages } = useChatMessages(sessionId);\n\n const executeGroqStream = useCallback(\n async (conv: ChatMessage[], effectiveSessionId: string | null, userMessage: ChatMessage) => {\n abortRef.current = new AbortController();\n const chatMessages = conv.map((m) => ({ role: m.role, content: m.content }));\n let doingChunkedReveal = false;\n try {\n const g = global as Record<string, unknown>;\n const preferNonStreaming =\n typeof g?.nativeCallSyncHook === 'function' || typeof g?.__fbBatchedBridge !== 'undefined';\n const result = await streamChatResponse(chatMessages, undefined, abortRef.current.signal, {\n preferNonStreaming,\n });\n const fullContent = result.content;\n\n if (preferNonStreaming && fullContent.length > 0) {\n doingChunkedReveal = true;\n if (revealIntervalRef.current) {\n clearInterval(revealIntervalRef.current);\n revealIntervalRef.current = null;\n }\n let revealedLen = 0;\n revealIntervalRef.current = setInterval(() => {\n revealedLen = Math.min(revealedLen + REVEAL_CHUNK_SIZE, fullContent.length);\n setResponse(fullContent.slice(0, revealedLen));\n if (revealedLen >= fullContent.length) {\n if (revealIntervalRef.current) {\n clearInterval(revealIntervalRef.current);\n revealIntervalRef.current = null;\n }\n const assistantMessage: ChatMessage = {\n role: 'assistant',\n content: fullContent,\n metadata: result.tokenUsage\n ? {\n tokenUsage: {\n inputTokens: result.tokenUsage.inputTokens,\n outputTokens: result.tokenUsage.outputTokens,\n totalTokens: result.tokenUsage.totalTokens,\n },\n }\n : undefined,\n };\n setMessages((prev) => [...prev, assistantMessage]);\n setResponse('');\n if (effectiveSessionId) {\n saveMessages({\n sessionId: effectiveSessionId,\n userMessage: {\n content: userMessage.content,\n attachments: userMessage.attachments?.map((a) => ({\n id: a.id,\n name: a.name,\n type: a.type,\n mimeType: a.mimeType,\n size: a.size,\n url: a.url,\n })),\n },\n assistantMessage: {\n content: fullContent,\n tokenCount: result.tokenUsage?.totalTokens,\n model: undefined,\n },\n }).catch((e) => console.error('[useChatStream] saveMessages (fallback):', e));\n }\n isSendingRef.current = false;\n setIsLoading(false);\n setIsStreaming(false);\n abortRef.current = null;\n userMsgForSaveRef.current = null;\n saveSessionIdRef.current = null;\n }\n }, REVEAL_INTERVAL_MS);\n return;\n }\n\n const assistantMessage: ChatMessage = {\n role: 'assistant',\n content: fullContent,\n metadata: result.tokenUsage\n ? {\n tokenUsage: {\n inputTokens: result.tokenUsage.inputTokens,\n outputTokens: result.tokenUsage.outputTokens,\n totalTokens: result.tokenUsage.totalTokens,\n },\n }\n : undefined,\n };\n\n setMessages((prev) => [...prev, assistantMessage]);\n setResponse('');\n\n if (effectiveSessionId) {\n await saveMessages({\n sessionId: effectiveSessionId,\n userMessage: {\n content: userMessage.content,\n attachments: userMessage.attachments?.map((a) => ({\n id: a.id,\n name: a.name,\n type: a.type,\n mimeType: a.mimeType,\n size: a.size,\n url: a.url,\n })),\n },\n assistantMessage: {\n content: fullContent,\n tokenCount: result.tokenUsage?.totalTokens,\n model: undefined,\n },\n });\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n if (!msg.includes('abort')) setError(msg);\n setResponse('');\n } finally {\n if (!doingChunkedReveal) {\n isSendingRef.current = false;\n setIsLoading(false);\n setIsStreaming(false);\n abortRef.current = null;\n userMsgForSaveRef.current = null;\n saveSessionIdRef.current = null;\n }\n }\n },\n [saveMessages],\n );\n\n const streamChannelId = sessionId || cdecliStreamOverrideId;\n\n const isCdecliActive = routing.kind === 'cdecli' && routing.channelConnected;\n\n const cdecliCallbacks = useMemo(\n () => ({\n onChunk: (text: string) => {\n if (routingRef.current.kind !== 'cdecli') return;\n setResponse((r) => r + text);\n },\n onComplete: (text: string) => {\n if (routingRef.current.kind !== 'cdecli') return;\n if (cdecliRoundHandledRef.current) {\n return;\n }\n\n if (isCdecliAgentFailureOutput(text)) {\n cdecliRoundHandledRef.current = true;\n console.warn('[useChatStream] CDeCLI agent error output; retrying via direct chat API');\n const sid = saveSessionIdRef.current;\n const um = userMsgForSaveRef.current;\n const conv = cdecliFallbackConversationRef.current;\n setResponse('');\n setError(null);\n userMsgForSaveRef.current = um;\n saveSessionIdRef.current = sid;\n setIsLoading(true);\n setIsStreaming(true);\n isSendingRef.current = true;\n if (conv?.length && um) {\n void executeGroqStream(conv, sid, um);\n return;\n }\n setMessages((prev) => [...prev, { role: 'assistant' as const, content: text }]);\n setIsLoading(false);\n setIsStreaming(false);\n isSendingRef.current = false;\n userMsgForSaveRef.current = null;\n saveSessionIdRef.current = null;\n return;\n }\n\n cdecliRoundHandledRef.current = true;\n\n const sid = saveSessionIdRef.current;\n const um = userMsgForSaveRef.current;\n saveSessionIdRef.current = null;\n userMsgForSaveRef.current = null;\n\n setMessages((prev) => [...prev, { role: 'assistant' as const, content: text }]);\n setResponse('');\n setIsLoading(false);\n setIsStreaming(false);\n isSendingRef.current = false;\n\n const rt = routingRef.current;\n const persistClientSide = rt.kind === 'cdecli' && rt.persistenceMode !== 'backend';\n\n if (sid && um && persistClientSide) {\n void saveMessages({\n sessionId: sid,\n userMessage: {\n content: um.content,\n attachments: um.attachments?.map((a) => ({\n id: a.id,\n name: a.name,\n type: a.type,\n mimeType: a.mimeType,\n size: a.size,\n url: a.url,\n })),\n },\n assistantMessage: {\n content: text,\n tokenCount: undefined,\n model: 'cdecli-serve',\n },\n }).catch((e) => console.error('[useChatStream] saveMessages (cdecli):', e));\n }\n },\n onError: (err: string) => {\n if (routingRef.current.kind !== 'cdecli') return;\n if (cdecliRoundHandledRef.current) return;\n const conv = cdecliFallbackConversationRef.current;\n const um = userMsgForSaveRef.current;\n const sid = saveSessionIdRef.current;\n if (conv?.length && um) {\n cdecliRoundHandledRef.current = true;\n console.warn(\n '[useChatStream] CDeCLI transport/stream error; falling back to direct chat API:',\n err,\n );\n setResponse('');\n setError(null);\n userMsgForSaveRef.current = um;\n saveSessionIdRef.current = sid;\n setIsLoading(true);\n setIsStreaming(true);\n isSendingRef.current = true;\n void executeGroqStream(conv, sid, um);\n return;\n }\n cdecliRoundHandledRef.current = false;\n setError(err);\n setResponse('');\n setIsLoading(false);\n setIsStreaming(false);\n isSendingRef.current = false;\n userMsgForSaveRef.current = null;\n saveSessionIdRef.current = null;\n },\n }),\n [saveMessages, executeGroqStream],\n );\n\n const { sendMessage: sendCdecliMessage } = useCdecliChannel(\n routing.kind === 'cdecli',\n isCdecliActive,\n routing.kind === 'cdecli' ? routing.accountId : 'default',\n streamChannelId,\n cdecliCallbacks,\n );\n\n useEffect(\n () => () => {\n if (revealIntervalRef.current) {\n clearInterval(revealIntervalRef.current);\n revealIntervalRef.current = null;\n }\n },\n [],\n );\n\n // Clear override once Apollo session id matches\n useEffect(() => {\n if (sessionId && cdecliStreamOverrideId && sessionId === cdecliStreamOverrideId) {\n setCdecliStreamOverrideId(undefined);\n }\n }, [sessionId, cdecliStreamOverrideId]);\n\n useEffect(() => {\n if (isSendingRef.current) return;\n\n if (!sessionId) {\n setMessages([]);\n setResponse('');\n return;\n }\n if (backendMessages && backendMessages.length > 0) {\n const formatted: ChatMessage[] = backendMessages.map((msg) => ({\n role: msg.role as 'user' | 'assistant',\n content: msg.content ?? '',\n metadata: msg.tokenCount\n ? {\n tokenUsage: {\n inputTokens: 0,\n outputTokens: msg.tokenCount,\n totalTokens: msg.tokenCount,\n },\n model: msg.model,\n }\n : undefined,\n }));\n setMessages(formatted);\n setResponse('');\n }\n }, [sessionId, backendMessages]);\n\n const sendMessage = useCallback(\n async (content: string, attachments?: MessageAttachment[], sessionIdOverride?: string | null) => {\n if (!content.trim()) return;\n\n const effectiveSessionId = sessionIdOverride !== undefined ? sessionIdOverride : sessionId;\n\n const userMessage: ChatMessage = {\n role: 'user',\n content: content.trim(),\n attachments,\n };\n\n isSendingRef.current = true;\n setMessages((prev) => [...prev, userMessage]);\n setResponse('');\n setIsLoading(true);\n setIsStreaming(true);\n setError(null);\n userMsgForSaveRef.current = userMessage;\n saveSessionIdRef.current = effectiveSessionId ?? null;\n cdecliRoundHandledRef.current = false;\n\n const rt = routingRef.current;\n if (rt.kind === 'cdecli') {\n if (!rt.channelConnected) {\n setError('CDeCLI is not connected yet. Check gateway status in the header.');\n setMessages((p) => p.slice(0, -1));\n isSendingRef.current = false;\n setIsLoading(false);\n setIsStreaming(false);\n userMsgForSaveRef.current = null;\n saveSessionIdRef.current = null;\n return;\n }\n if (!effectiveSessionId) {\n setError('Missing chat session id.');\n setMessages((p) => p.slice(0, -1));\n isSendingRef.current = false;\n setIsLoading(false);\n setIsStreaming(false);\n userMsgForSaveRef.current = null;\n saveSessionIdRef.current = null;\n return;\n }\n\n if (sessionIdOverride) {\n setCdecliStreamOverrideId(sessionIdOverride);\n await new Promise<void>((r) => setTimeout(r, 0));\n }\n\n cdecliFallbackConversationRef.current = [...messages, userMessage];\n\n const ok = await sendCdecliMessage(content.trim(), effectiveSessionId);\n if (!ok && !cdecliRoundHandledRef.current) {\n const conv = cdecliFallbackConversationRef.current;\n console.warn('[useChatStream] CDeCLI send returned false; falling back to direct chat API');\n cdecliRoundHandledRef.current = true;\n userMsgForSaveRef.current = userMessage;\n saveSessionIdRef.current = effectiveSessionId ?? null;\n void executeGroqStream(conv ?? [], effectiveSessionId ?? null, userMessage);\n return;\n }\n return;\n }\n\n await executeGroqStream([...messages, userMessage], effectiveSessionId ?? null, userMessage);\n },\n [messages, sessionId, sendCdecliMessage, executeGroqStream],\n );\n\n const cancel = useCallback(() => {\n if (abortRef.current) {\n abortRef.current.abort();\n }\n }, []);\n\n const clearMessages = useCallback(() => {\n setMessages([]);\n setResponse('');\n setError(null);\n }, []);\n\n return {\n messages,\n response,\n error,\n isLoading,\n isStreaming,\n hasMessages: messages.length > 0 || !!response,\n sendMessage,\n cancel,\n clearMessages,\n };\n}\n"],"names":["_a","_b","assistantMessage","sid","um"],"mappings":"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"}
@@ -0,0 +1,123 @@
1
+ import {useApolloClient}from'@apollo/client/index.js';import {useState,useRef,useCallback,useEffect}from'react';import {config}from'../config/env-config.js';import {OPENCLAW_CHAT_CONNECTION_QUERY}from'../graphql/agentGatewayDocuments.js';import {agentSessionManager}from'../services/agentSessionManager.js';import {GatewayClient}from'../services/gatewayClient.js';function isInstanceNotFoundError(error) {
2
+ if (!error) return false;
3
+ return error.includes("Instance not found") || error.includes("is the workspace running");
4
+ }
5
+ const MAX_CONNECT_RETRIES = 6;
6
+ const RETRY_BASE_DELAY_MS = 2e3;
7
+ const MAX_RETRY_DELAY_MS = 8e3;
8
+ function isTransientConnectionError(msg) {
9
+ return msg.includes("connection closed before handshake") || msg.includes("WebSocket connection error") || msg.includes("Failed to fetch") || msg.includes("Gateway GraphQL request failed: 5");
10
+ }
11
+ function useGatewayConnection(projectId, userId) {
12
+ var _a;
13
+ const client = useApolloClient();
14
+ const [status, setStatus] = useState(() => {
15
+ var _a2;
16
+ return ((_a2 = agentSessionManager.getClient()) == null ? void 0 : _a2.connected) ? "connected" : "disconnected";
17
+ });
18
+ const [error, setError] = useState(null);
19
+ const clientRef = useRef((_a = agentSessionManager.getClient()) != null ? _a : null);
20
+ const connectingRef = useRef(false);
21
+ const fetchGatewayConnection = useCallback(async (pid, uid) => {
22
+ var _a2;
23
+ const res = await client.query({
24
+ query: OPENCLAW_CHAT_CONNECTION_QUERY,
25
+ variables: {
26
+ projectId: pid,
27
+ userId: uid
28
+ },
29
+ fetchPolicy: "network-only"
30
+ });
31
+ if ((_a2 = res.errors) == null ? void 0 : _a2.length) throw new Error(res.errors[0].message);
32
+ const data = res.data;
33
+ const conn = data == null ? void 0 : data.openclawChatConnection;
34
+ if (!conn) throw new Error("No openclawChatConnection in response");
35
+ return conn;
36
+ }, [client]);
37
+ const disconnect = useCallback(() => {
38
+ if (clientRef.current) {
39
+ clientRef.current.close();
40
+ clientRef.current = null;
41
+ }
42
+ agentSessionManager.detachGateway();
43
+ setStatus("disconnected");
44
+ setError(null);
45
+ connectingRef.current = false;
46
+ }, []);
47
+ const connect = useCallback(async () => {
48
+ var _a2;
49
+ if (connectingRef.current) {
50
+ console.log("[Gateway] Connection already in progress, skipping");
51
+ return;
52
+ }
53
+ if ((_a2 = agentSessionManager.getClient()) == null ? void 0 : _a2.connected) {
54
+ clientRef.current = agentSessionManager.getClient();
55
+ setStatus("connected");
56
+ return;
57
+ }
58
+ if (!projectId || !userId) {
59
+ console.warn("[Gateway] Cannot connect \u2014 projectId or userId is not available yet");
60
+ return;
61
+ }
62
+ connectingRef.current = true;
63
+ console.log("[Gateway] Connecting to gateway...");
64
+ if (clientRef.current) {
65
+ clientRef.current.close();
66
+ clientRef.current = null;
67
+ agentSessionManager.detachGateway();
68
+ }
69
+ setStatus("connecting");
70
+ setError(null);
71
+ let lastError = null;
72
+ for (let attempt = 1; attempt <= MAX_CONNECT_RETRIES; attempt++) {
73
+ try {
74
+ const conn = await fetchGatewayConnection(projectId, userId);
75
+ if (!(conn == null ? void 0 : conn.proxyToken)) {
76
+ throw new Error("No gateway connection available \u2014 is the workspace running?");
77
+ }
78
+ console.log(`[Gateway] Connecting (attempt ${attempt}/${MAX_CONNECT_RETRIES}): wsUrl=${conn.wsUrl} url=${conn.url} proxyWs=${config.AGENT_GATEWAY_WS_URL}`);
79
+ const wsUrl = config.AGENT_GATEWAY_WS_URL;
80
+ const wsClient = new GatewayClient(wsUrl, conn.token, conn.proxyToken);
81
+ clientRef.current = wsClient;
82
+ const hello = await wsClient.connect();
83
+ await agentSessionManager.attachGateway(wsClient, hello);
84
+ console.log("[Gateway] Connected successfully");
85
+ setStatus("connected");
86
+ connectingRef.current = false;
87
+ wsClient.on("disconnect", () => {
88
+ setStatus("disconnected");
89
+ connectingRef.current = false;
90
+ });
91
+ return;
92
+ } catch (err) {
93
+ const msg = err instanceof Error ? err.message : String(err);
94
+ lastError = msg;
95
+ if (clientRef.current) {
96
+ clientRef.current.close();
97
+ clientRef.current = null;
98
+ }
99
+ if (!isTransientConnectionError(msg) || attempt >= MAX_CONNECT_RETRIES) {
100
+ break;
101
+ }
102
+ const retryDelay = Math.min(RETRY_BASE_DELAY_MS * 2 ** (attempt - 1), MAX_RETRY_DELAY_MS);
103
+ console.warn(`[Gateway] Transient failure (attempt ${attempt}/${MAX_CONNECT_RETRIES}): ${msg} \u2014 retrying in ${retryDelay / 1e3}s`);
104
+ await new Promise((r) => {
105
+ setTimeout(r, retryDelay);
106
+ });
107
+ }
108
+ }
109
+ console.error(`[Gateway] Connection failed after ${MAX_CONNECT_RETRIES} attempts: ${lastError} (projectId=${projectId}, userId=${userId}, wsUrl=${config.AGENT_GATEWAY_WS_URL})`);
110
+ setStatus("error");
111
+ setError(lastError);
112
+ connectingRef.current = false;
113
+ }, [projectId, userId, fetchGatewayConnection]);
114
+ useEffect(() => () => {
115
+ connectingRef.current = false;
116
+ }, []);
117
+ return {
118
+ status,
119
+ error,
120
+ connect,
121
+ disconnect
122
+ };
123
+ }export{isInstanceNotFoundError,useGatewayConnection};//# sourceMappingURL=useGatewayConnection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGatewayConnection.js","sources":["../../src/hooks/useGatewayConnection.ts"],"sourcesContent":["/**\n * OpenClaw gateway WebSocket — same flow as account/browser, using Apollo\n * for `openclawChatConnection` so mobile gets the same auth as other operations.\n */\n\nimport { useApolloClient } from '@apollo/client';\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport { config } from '../config/env-config';\nimport { OPENCLAW_CHAT_CONNECTION_QUERY } from '../graphql/agentGatewayDocuments';\nimport { GatewayClient, agentSessionManager, resetGatewayApiKeyBridge } from '../services';\n\nexport type GatewayConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'error';\n\nexport interface UseGatewayConnectionResult {\n status: GatewayConnectionStatus;\n error: string | null;\n connect: () => Promise<void>;\n disconnect: () => void;\n}\n\nexport function isInstanceNotFoundError(error: string | null): boolean {\n if (!error) return false;\n return error.includes('Instance not found') || error.includes('is the workspace running');\n}\n\nconst MAX_CONNECT_RETRIES = 6;\nconst RETRY_BASE_DELAY_MS = 2000;\nconst MAX_RETRY_DELAY_MS = 8000;\n\nfunction isTransientConnectionError(msg: string): boolean {\n return (\n msg.includes('connection closed before handshake') ||\n msg.includes('WebSocket connection error') ||\n msg.includes('Failed to fetch') ||\n msg.includes('Gateway GraphQL request failed: 5')\n );\n}\n\nexport function useGatewayConnection(projectId: string | null, userId: string | null): UseGatewayConnectionResult {\n const client = useApolloClient();\n const [status, setStatus] = useState<GatewayConnectionStatus>(() =>\n agentSessionManager.getClient()?.connected ? 'connected' : 'disconnected',\n );\n const [error, setError] = useState<string | null>(null);\n const clientRef = useRef<GatewayClient | null>(agentSessionManager.getClient() ?? null);\n const connectingRef = useRef(false);\n\n const fetchGatewayConnection = useCallback(\n async (\n pid: string,\n uid: string,\n ): Promise<{ wsUrl: string; token: string; url: string; proxyToken: string; expiresAt: string }> => {\n const res = await client.query({\n query: OPENCLAW_CHAT_CONNECTION_QUERY,\n variables: { projectId: pid, userId: uid },\n fetchPolicy: 'network-only',\n });\n if (res.errors?.length) throw new Error(res.errors[0].message);\n const data = res.data as {\n openclawChatConnection: {\n wsUrl: string;\n token: string;\n url: string;\n proxyToken: string;\n expiresAt: string;\n };\n };\n const conn = data?.openclawChatConnection;\n if (!conn) throw new Error('No openclawChatConnection in response');\n return conn;\n },\n [client],\n );\n\n const disconnect = useCallback(() => {\n if (clientRef.current) {\n clientRef.current.close();\n clientRef.current = null;\n }\n agentSessionManager.detachGateway();\n resetGatewayApiKeyBridge();\n setStatus('disconnected');\n setError(null);\n connectingRef.current = false;\n }, []);\n\n const connect = useCallback(async () => {\n if (connectingRef.current) {\n console.log('[Gateway] Connection already in progress, skipping');\n return;\n }\n if (agentSessionManager.getClient()?.connected) {\n clientRef.current = agentSessionManager.getClient();\n setStatus('connected');\n return;\n }\n if (!projectId || !userId) {\n console.warn('[Gateway] Cannot connect — projectId or userId is not available yet');\n return;\n }\n connectingRef.current = true;\n console.log('[Gateway] Connecting to gateway...');\n\n if (clientRef.current) {\n clientRef.current.close();\n clientRef.current = null;\n agentSessionManager.detachGateway();\n }\n\n setStatus('connecting');\n setError(null);\n\n let lastError: string | null = null;\n\n for (let attempt = 1; attempt <= MAX_CONNECT_RETRIES; attempt++) {\n try {\n const conn = await fetchGatewayConnection(projectId, userId);\n if (!conn?.proxyToken) {\n throw new Error('No gateway connection available — is the workspace running?');\n }\n console.log(\n `[Gateway] Connecting (attempt ${attempt}/${MAX_CONNECT_RETRIES}): wsUrl=${conn.wsUrl} url=${conn.url} proxyWs=${config.AGENT_GATEWAY_WS_URL}`,\n );\n\n const wsUrl = config.AGENT_GATEWAY_WS_URL;\n const wsClient = new GatewayClient(wsUrl, conn.token, conn.proxyToken);\n clientRef.current = wsClient;\n\n const hello = await wsClient.connect();\n await agentSessionManager.attachGateway(wsClient, hello);\n\n console.log('[Gateway] Connected successfully');\n setStatus('connected');\n connectingRef.current = false;\n\n wsClient.on('disconnect', () => {\n setStatus('disconnected');\n connectingRef.current = false;\n });\n return;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n lastError = msg;\n\n if (clientRef.current) {\n clientRef.current.close();\n clientRef.current = null;\n }\n\n if (!isTransientConnectionError(msg) || attempt >= MAX_CONNECT_RETRIES) {\n break;\n }\n\n const retryDelay = Math.min(RETRY_BASE_DELAY_MS * 2 ** (attempt - 1), MAX_RETRY_DELAY_MS);\n console.warn(\n `[Gateway] Transient failure (attempt ${attempt}/${MAX_CONNECT_RETRIES}): ${msg} — retrying in ${retryDelay / 1000}s`,\n );\n await new Promise<void>((r) => {\n setTimeout(r, retryDelay);\n });\n }\n }\n\n console.error(\n `[Gateway] Connection failed after ${MAX_CONNECT_RETRIES} attempts: ${lastError} (projectId=${projectId}, userId=${userId}, wsUrl=${config.AGENT_GATEWAY_WS_URL})`,\n );\n setStatus('error');\n setError(lastError);\n connectingRef.current = false;\n }, [projectId, userId, fetchGatewayConnection]);\n\n useEffect(\n () => () => {\n connectingRef.current = false;\n },\n [],\n );\n\n return { status, error, connect, disconnect };\n}\n"],"names":["_a"],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import {useMemo}from'react';import {BUILTIN_MOBILE_GATEWAYS}from'../config/constants.js';var __defProp = Object.defineProperty;
2
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
3
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
4
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
5
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
+ var __spreadValues = (a, b) => {
7
+ for (var prop in b || (b = {}))
8
+ if (__hasOwnProp.call(b, prop))
9
+ __defNormalProp(a, prop, b[prop]);
10
+ if (__getOwnPropSymbols)
11
+ for (var prop of __getOwnPropSymbols(b)) {
12
+ if (__propIsEnum.call(b, prop))
13
+ __defNormalProp(a, prop, b[prop]);
14
+ }
15
+ return a;
16
+ };
17
+ function useGatewayRegistry() {
18
+ const gateways = useMemo(() => __spreadValues({}, BUILTIN_MOBILE_GATEWAYS), []);
19
+ const gatewayList = useMemo(() => Object.entries(gateways).map(([id, entry]) => __spreadValues({
20
+ id
21
+ }, entry)).sort((a, b) => b.priority - a.priority), [gateways]);
22
+ return {
23
+ gateways,
24
+ gatewayList,
25
+ loading: false,
26
+ error: false
27
+ };
28
+ }export{useGatewayRegistry};//# sourceMappingURL=useGatewayRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useGatewayRegistry.js","sources":["../../src/hooks/useGatewayRegistry.ts"],"sourcesContent":["/** Mobile gateway registry. Uses built-ins to avoid settings shape issues in RN runtime. */\n\nimport { useMemo } from 'react';\nimport { BUILTIN_MOBILE_GATEWAYS, type GatewayEntry } from '../config/constants';\n\nexport interface UseGatewayRegistryReturn {\n gateways: Record<string, GatewayEntry>;\n gatewayList: Array<{ id: string } & GatewayEntry>;\n loading: boolean;\n error: boolean;\n}\n\nexport function useGatewayRegistry(): UseGatewayRegistryReturn {\n const gateways = useMemo(() => ({ ...BUILTIN_MOBILE_GATEWAYS }), []);\n\n const gatewayList = useMemo(\n () =>\n Object.entries(gateways)\n .map(([id, entry]) => ({ id, ...entry }))\n .sort((a, b) => b.priority - a.priority),\n [gateways],\n );\n\n return { gateways, gatewayList, loading: false, error: false };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAYO,SAAS,kBAA+C,GAAA;AAC7D,EAAA,MAAM,WAAW,OAAQ,CAAA,MAAO,cAC3B,CAAA,EAAA,EAAA,uBAAA,CAAA,EACD,EAAE,CAAA;AACN,EAAA,MAAM,WAAc,GAAA,OAAA,CAAQ,MAAM,MAAA,CAAO,OAAQ,CAAA,QAAQ,CAAE,CAAA,GAAA,CAAI,CAAC,CAAC,EAAI,EAAA,KAAK,CAAO,KAAA,cAAA,CAAA;AAAA,IAC/E;AAAA,GAAA,EACG,KACH,CAAA,CAAA,CAAE,IAAK,CAAA,CAAC,CAAG,EAAA,CAAA,KAAM,CAAE,CAAA,QAAA,GAAW,CAAE,CAAA,QAAQ,CAAG,EAAA,CAAC,QAAQ,CAAC,CAAA;AACvD,EAAO,OAAA;AAAA,IACL,QAAA;AAAA,IACA,WAAA;AAAA,IACA,OAAS,EAAA,KAAA;AAAA,IACT,KAAO,EAAA;AAAA,GACT;AACF"}