@adminide-stack/yantra-mobile 12.0.28-alpha.74 → 12.0.28-alpha.75
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/config/constants.js +3 -1
- package/lib/config/constants.js.map +1 -1
- package/lib/config/env-config.js +2 -1
- package/lib/config/env-config.js.map +1 -1
- package/lib/hooks/useCdecliAutoConnect.js +4 -2
- package/lib/hooks/useCdecliAutoConnect.js.map +1 -1
- package/lib/hooks/useCdecliChannel.js +18 -83
- package/lib/hooks/useCdecliChannel.js.map +1 -1
- package/lib/hooks/useChatApi.js +102 -50
- package/lib/hooks/useChatApi.js.map +1 -1
- package/lib/hooks/useChatStream.js +66 -241
- package/lib/hooks/useChatStream.js.map +1 -1
- package/lib/hooks/usePrerequisiteIds.js +87 -75
- package/lib/hooks/usePrerequisiteIds.js.map +1 -1
- package/lib/screens/Chat/index.js +6 -11
- package/lib/screens/Chat/index.js.map +1 -1
- package/lib/screens/Home/HomeScreen.js +37 -84
- package/lib/screens/Home/HomeScreen.js.map +1 -1
- package/lib/screens/NewChat/index.js +8 -44
- package/lib/screens/NewChat/index.js.map +1 -1
- package/lib/utils/cdecodeUri.js +69 -0
- package/lib/utils/cdecodeUri.js.map +1 -0
- package/lib/utils/syncMobileOrgRouteContext.js +61 -0
- package/lib/utils/syncMobileOrgRouteContext.js.map +1 -0
- package/package.json +3 -3
- package/lib/api/chatApi.js +0 -102
- package/lib/api/chatApi.js.map +0 -1
package/lib/config/constants.js
CHANGED
|
@@ -5,7 +5,9 @@ const CDECLI_GATEWAY = {
|
|
|
5
5
|
extensionId: "",
|
|
6
6
|
icon: "terminal",
|
|
7
7
|
isBuiltin: true,
|
|
8
|
-
priority: 90
|
|
8
|
+
priority: 90,
|
|
9
|
+
/** Server persists chat posts via gateway — client must not call `saveMessages`. */
|
|
10
|
+
persistenceMode: "backend"
|
|
9
11
|
};
|
|
10
12
|
const BUILTIN_MOBILE_GATEWAYS = {
|
|
11
13
|
cdecli: CDECLI_GATEWAY
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sources":["../../src/config/constants.ts"],"sourcesContent":["/** Minimal gateway types for mobile — aligned with account/browser. */\n\nexport type GatewayId = string;\n\nexport interface GatewayEntry {\n name: string;\n description: string;\n channelType: string;\n extensionId: string;\n icon: string;\n isBuiltin: boolean;\n priority: number;\n endpoint?: string;\n persistenceMode?: 'backend' | 'frontend';\n}\n\n/** CDeCLI / cdecli-serve (hosted agent). */\nconst CDECLI_GATEWAY: GatewayEntry = {\n name: 'CDeCLI',\n description: 'CDeCLI agent and skills',\n channelType: 'cdecli-serve',\n extensionId: '',\n icon: 'terminal',\n isBuiltin: true,\n priority: 90,\n};\n\n/** Built-in gateways when UiLayout settings are not loaded (e.g. React Native). */\nexport const BUILTIN_MOBILE_GATEWAYS: Record<string, GatewayEntry> = {\n cdecli: CDECLI_GATEWAY,\n};\n\nexport const STORAGE_KEYS = {\n GATEWAY_SELECTION: 'yantra_gateway_selection',\n} as const;\n\n/** Maximum concurrent agent tasks (same cap as browser). */\nexport const MAX_CONCURRENT_TASKS = 3;\n"],"names":[],"mappings":"AAgBA,MAAM,cAA+B,GAAA;AAAA,EACnC,IAAM,EAAA,QAAA;AAAA,EACN,WAAa,EAAA,yBAAA;AAAA,EACb,WAAa,EAAA,cAAA;AAAA,EACb,WAAa,EAAA,EAAA;AAAA,EACb,IAAM,EAAA,UAAA;AAAA,EACN,SAAW,EAAA,IAAA;AAAA,EACX,QAAU,EAAA;
|
|
1
|
+
{"version":3,"file":"constants.js","sources":["../../src/config/constants.ts"],"sourcesContent":["/** Minimal gateway types for mobile — aligned with account/browser. */\n\nexport type GatewayId = string;\n\nexport interface GatewayEntry {\n name: string;\n description: string;\n channelType: string;\n extensionId: string;\n icon: string;\n isBuiltin: boolean;\n priority: number;\n endpoint?: string;\n persistenceMode?: 'backend' | 'frontend';\n}\n\n/** CDeCLI / cdecli-serve (hosted agent). */\nconst CDECLI_GATEWAY: GatewayEntry = {\n name: 'CDeCLI',\n description: 'CDeCLI agent and skills',\n channelType: 'cdecli-serve',\n extensionId: '',\n icon: 'terminal',\n isBuiltin: true,\n priority: 90,\n /** Server persists chat posts via gateway — client must not call `saveMessages`. */\n persistenceMode: 'backend',\n};\n\n/** Built-in gateways when UiLayout settings are not loaded (e.g. React Native). */\nexport const BUILTIN_MOBILE_GATEWAYS: Record<string, GatewayEntry> = {\n cdecli: CDECLI_GATEWAY,\n};\n\nexport const STORAGE_KEYS = {\n GATEWAY_SELECTION: 'yantra_gateway_selection',\n} as const;\n\n/** Maximum concurrent agent tasks (same cap as browser). */\nexport const MAX_CONCURRENT_TASKS = 3;\n"],"names":[],"mappings":"AAgBA,MAAM,cAA+B,GAAA;AAAA,EACnC,IAAM,EAAA,QAAA;AAAA,EACN,WAAa,EAAA,yBAAA;AAAA,EACb,WAAa,EAAA,cAAA;AAAA,EACb,WAAa,EAAA,EAAA;AAAA,EACb,IAAM,EAAA,UAAA;AAAA,EACN,SAAW,EAAA,IAAA;AAAA,EACX,QAAU,EAAA,EAAA;AAAA;AAAA,EAEV,eAAiB,EAAA;AACnB,CAAA;AAGO,MAAM,uBAAwD,GAAA;AAAA,EACnE,MAAQ,EAAA;AACV;AACO,MAAM,YAAe,GAAA;AAAA,EAC1B,iBAAmB,EAAA;AACrB;AAGO,MAAM,oBAAuB,GAAA"}
|
package/lib/config/env-config.js
CHANGED
|
@@ -38,8 +38,9 @@ const baseConfig = cleanEnv(env, {
|
|
|
38
38
|
default: ""
|
|
39
39
|
}),
|
|
40
40
|
/** Seconds to wait for CDeCLI stream completion before timing out (then fallback chat API runs). Min 15, max 600. */
|
|
41
|
+
/** Aligned with web `useCdecliChannel` (120s). Mobile hook uses the same constant inline. */
|
|
41
42
|
CDECLI_CHAT_RESPONSE_TIMEOUT_SEC: num({
|
|
42
|
-
default:
|
|
43
|
+
default: 120
|
|
43
44
|
}),
|
|
44
45
|
BACKEND_URL: str({
|
|
45
46
|
default: ""
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env-config.js","sources":["../../src/config/env-config.ts"],"sourcesContent":["import { str, cleanEnv, bool, num } from 'envalid';\n\nconst env = (process as { APP_ENV?: NodeJS.ProcessEnv; env?: NodeJS.ProcessEnv }).APP_ENV || process.env;\n\nconst baseConfig = cleanEnv(env, {\n GRAPHQL_URL: str({ default: 'http://localhost:8080/graphql' }),\n CLIENT_URL: str({ default: 'http://localhost:3000' }),\n APP_NAME: str({ default: 'Yantra' }),\n GROQ_API_KEY: str({ default: '' }),\n CDECLI_AGENT_ENDPOINT: str({ default: 'https://cdecli-agent.cdebase.dev' }),\n CDECLI_AGENT_AUTH_TOKEN: str({ default: '' }),\n /** Seconds to wait for CDeCLI stream completion before timing out (then fallback chat API runs). Min 15, max 600. */\n CDECLI_CHAT_RESPONSE_TIMEOUT_SEC: num({ default:
|
|
1
|
+
{"version":3,"file":"env-config.js","sources":["../../src/config/env-config.ts"],"sourcesContent":["import { str, cleanEnv, bool, num } from 'envalid';\n\nconst env = (process as { APP_ENV?: NodeJS.ProcessEnv; env?: NodeJS.ProcessEnv }).APP_ENV || process.env;\n\nconst baseConfig = cleanEnv(env, {\n GRAPHQL_URL: str({ default: 'http://localhost:8080/graphql' }),\n CLIENT_URL: str({ default: 'http://localhost:3000' }),\n APP_NAME: str({ default: 'Yantra' }),\n GROQ_API_KEY: str({ default: '' }),\n CDECLI_AGENT_ENDPOINT: str({ default: 'https://cdecli-agent.cdebase.dev' }),\n CDECLI_AGENT_AUTH_TOKEN: str({ default: '' }),\n /** Seconds to wait for CDeCLI stream completion before timing out (then fallback chat API runs). Min 15, max 600. */\n /** Aligned with web `useCdecliChannel` (120s). Mobile hook uses the same constant inline. */\n CDECLI_CHAT_RESPONSE_TIMEOUT_SEC: num({ default: 120 }),\n BACKEND_URL: str({ default: '' }),\n USE_PROXY_STAGING_GATEWAY: bool({ default: false }),\n PROXY_STAGING_GATEWAY_URL: str({ default: '' }),\n});\n\nfunction resolveAgentGatewayGraphqlUrl(): string {\n if (baseConfig.USE_PROXY_STAGING_GATEWAY && baseConfig.PROXY_STAGING_GATEWAY_URL) {\n return baseConfig.PROXY_STAGING_GATEWAY_URL;\n }\n if (baseConfig.GRAPHQL_URL) return baseConfig.GRAPHQL_URL;\n if (baseConfig.BACKEND_URL) return `${baseConfig.BACKEND_URL.replace(/\\/$/, '')}/graphql`;\n return '/graphql';\n}\n\nfunction resolveBaseWsUrl(graphqlUrl: string): string {\n const base = graphqlUrl.replace(/\\/graphql$/, '');\n return base.replace(/^http/, 'ws');\n}\n\nfunction resolveAgentGatewayWsUrl(graphqlUrl: string): string {\n return `${resolveBaseWsUrl(graphqlUrl)}/ws/openclaw-chat`;\n}\n\nconst agentGatewayGraphqlUrl = resolveAgentGatewayGraphqlUrl();\n\nconst clampedCdecliTimeoutSec = Math.min(600, Math.max(15, Math.round(baseConfig.CDECLI_CHAT_RESPONSE_TIMEOUT_SEC)));\n\nexport const config = {\n ...baseConfig,\n CDECLI_CHAT_RESPONSE_TIMEOUT_SEC: clampedCdecliTimeoutSec,\n AGENT_GATEWAY_GRAPHQL_URL: agentGatewayGraphqlUrl,\n AGENT_GATEWAY_WS_URL: resolveAgentGatewayWsUrl(agentGatewayGraphqlUrl),\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AACA,MAAM,GAAA,GAAO,OAGV,CAAA,OAAA,IAAW,OAAQ,CAAA,GAAA;AACtB,MAAM,UAAA,GAAa,SAAS,GAAK,EAAA;AAAA,EAC/B,aAAa,GAAI,CAAA;AAAA,IACf,OAAS,EAAA;AAAA,GACV,CAAA;AAAA,EACD,YAAY,GAAI,CAAA;AAAA,IACd,OAAS,EAAA;AAAA,GACV,CAAA;AAAA,EACD,UAAU,GAAI,CAAA;AAAA,IACZ,OAAS,EAAA;AAAA,GACV,CAAA;AAAA,EACD,cAAc,GAAI,CAAA;AAAA,IAChB,OAAS,EAAA;AAAA,GACV,CAAA;AAAA,EACD,uBAAuB,GAAI,CAAA;AAAA,IACzB,OAAS,EAAA;AAAA,GACV,CAAA;AAAA,EACD,yBAAyB,GAAI,CAAA;AAAA,IAC3B,OAAS,EAAA;AAAA,GACV,CAAA;AAAA;AAAA;AAAA,EAGD,kCAAkC,GAAI,CAAA;AAAA,IACpC,OAAS,EAAA;AAAA,GACV,CAAA;AAAA,EACD,aAAa,GAAI,CAAA;AAAA,IACf,OAAS,EAAA;AAAA,GACV,CAAA;AAAA,EACD,2BAA2B,IAAK,CAAA;AAAA,IAC9B,OAAS,EAAA;AAAA,GACV,CAAA;AAAA,EACD,2BAA2B,GAAI,CAAA;AAAA,IAC7B,OAAS,EAAA;AAAA,GACV;AACH,CAAC,CAAA;AACD,SAAS,6BAAwC,GAAA;AAC/C,EAAI,IAAA,UAAA,CAAW,yBAA6B,IAAA,UAAA,CAAW,yBAA2B,EAAA;AAChF,IAAA,OAAO,UAAW,CAAA,yBAAA;AAAA;AAEpB,EAAI,IAAA,UAAA,CAAW,WAAa,EAAA,OAAO,UAAW,CAAA,WAAA;AAC9C,EAAI,IAAA,UAAA,CAAW,aAAoB,OAAA,CAAA,EAAG,WAAW,WAAY,CAAA,OAAA,CAAQ,KAAO,EAAA,EAAE,CAAC,CAAA,QAAA,CAAA;AAC/E,EAAO,OAAA,UAAA;AACT;AACA,SAAS,iBAAiB,UAA4B,EAAA;AACpD,EAAA,MAAM,IAAO,GAAA,UAAA,CAAW,OAAQ,CAAA,YAAA,EAAc,EAAE,CAAA;AAChD,EAAO,OAAA,IAAA,CAAK,OAAQ,CAAA,OAAA,EAAS,IAAI,CAAA;AACnC;AACA,SAAS,yBAAyB,UAA4B,EAAA;AAC5D,EAAO,OAAA,CAAA,EAAG,gBAAiB,CAAA,UAAU,CAAC,CAAA,iBAAA,CAAA;AACxC;AACA,MAAM,yBAAyB,6BAA8B,EAAA;AAC7D,MAAM,uBAA0B,GAAA,IAAA,CAAK,GAAI,CAAA,GAAA,EAAK,IAAK,CAAA,GAAA,CAAI,EAAI,EAAA,IAAA,CAAK,KAAM,CAAA,UAAA,CAAW,gCAAgC,CAAC,CAAC,CAAA;AACtG,MAAA,MAAA,GAAS,iCACjB,UADiB,CAAA,EAAA;AAAA,EAEpB,gCAAkC,EAAA,uBAAA;AAAA,EAClC,yBAA2B,EAAA,sBAAA;AAAA,EAC3B,oBAAA,EAAsB,yBAAyB,sBAAsB;AACvE,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {useState,useRef,useCallback,useEffect}from'react';import {useGatewayConnectMutation,useGatewayDisconnectMutation,useCreateSecretApiTokenMutation,useRevealSecretApiTokenMutation,useGetUserSystemTokenQuery}from'common/graphql';import {config}from'../config/env-config.js';import {usePrerequisiteIds}from'./usePrerequisiteIds.js';var __defProp = Object.defineProperty;
|
|
1
|
+
import {useState,useRef,useCallback,useEffect}from'react';import {useGatewayConnectMutation,useGatewayDisconnectMutation,useCreateSecretApiTokenMutation,useRevealSecretApiTokenMutation,useGetUserSystemTokenQuery}from'common/graphql';import {SecretApiTokenAlgorithm}from'common';import {config}from'../config/env-config.js';import {usePrerequisiteIds}from'./usePrerequisiteIds.js';var __defProp = Object.defineProperty;
|
|
2
2
|
var __defProps = Object.defineProperties;
|
|
3
3
|
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
4
4
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
@@ -17,6 +17,7 @@ var __spreadValues = (a, b) => {
|
|
|
17
17
|
return a;
|
|
18
18
|
};
|
|
19
19
|
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
20
|
+
const SYSTEM_TOKEN_ALGORITHM = __DEV__ ? SecretApiTokenAlgorithm.Hs256 : SecretApiTokenAlgorithm.Rs256;
|
|
20
21
|
const CHANNEL_TYPE = "cdecli-serve";
|
|
21
22
|
function useCdecliAutoConnect(isSelected, channelId) {
|
|
22
23
|
const [status, setStatus] = useState("idle");
|
|
@@ -71,7 +72,8 @@ function useCdecliAutoConnect(isSelected, channelId) {
|
|
|
71
72
|
isSystemToken: true,
|
|
72
73
|
environmentTagId: tagId,
|
|
73
74
|
orgName: orgName || "default",
|
|
74
|
-
projectId: projectId || "default"
|
|
75
|
+
projectId: projectId || "default",
|
|
76
|
+
algorithm: SYSTEM_TOKEN_ALGORITHM
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
79
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCdecliAutoConnect.js","sources":["../../src/hooks/useCdecliAutoConnect.ts"],"sourcesContent":["/**\n * Auto-connects the cdecli-serve messenger-gateway channel when the CDeCLI\n * gateway is selected from the dropdown. Obtains/creates a system token and\n * calls the `gatewayConnect` mutation so the backend provider has a live\n * session with the cdecli-agent endpoint.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n useGatewayConnectMutation,\n useGatewayDisconnectMutation,\n useGetUserSystemTokenQuery,\n useCreateSecretApiTokenMutation,\n useRevealSecretApiTokenMutation,\n} from 'common/graphql';\nimport { config } from '../config/env-config';\nimport { usePrerequisiteIds } from './usePrerequisiteIds';\n\n// ─── Types ───────────────────────────────────────────────────────\n\nexport type CdecliAutoConnectStatus = 'idle' | 'connecting' | 'connected' | 'error';\n\nexport interface UseCdecliAutoConnectResult {\n /** Whether the backend cdecli-serve channel is connected. */\n channelConnected: boolean;\n /** Current connection status. */\n status: CdecliAutoConnectStatus;\n /** Error message if status is 'error'. */\n error: string | null;\n /** Persistence mode reported by the backend provider ('backend' | 'frontend'). */\n persistenceMode: 'backend' | 'frontend' | undefined;\n /** Active skill name on the current CDeCLI session (null if none). */\n activeSkill: string | null;\n /** Per-user accountId used for this gateway connection. */\n accountId: string;\n /** Reconnect the CDeCLI session with a specific skill pre-activated. */\n connectWithSkill: (skill: string, model?: string, systemPrompt?: string, skillId?: string) => Promise<void>;\n}\n\n// ─── Constants ───────────────────────────────────────────────────\n\nconst CHANNEL_TYPE = 'cdecli-serve';\n\n// ─── Hook ────────────────────────────────────────────────────────\n\n/**\n * When `isSelected` is true, auto-connects the cdecli-serve channel on the\n * messenger-gateway backend using the hosted endpoint and a system token.\n */\nexport function useCdecliAutoConnect(isSelected: boolean, channelId?: string): UseCdecliAutoConnectResult {\n const [status, setStatus] = useState<CdecliAutoConnectStatus>('idle');\n const [error, setError] = useState<string | null>(null);\n const [persistenceMode, setPersistenceMode] = useState<'backend' | 'frontend' | undefined>(undefined);\n const [activeSkill, setActiveSkill] = useState<string | null>(null);\n const connectingRef = useRef(false);\n const connectedRef = useRef(false);\n\n const { orgName, projectId, tagId, accountUserId, loading: prerequisitesLoading } = usePrerequisiteIds();\n\n // Per-user accountId so each user gets their own cdecli-agent session.\n // Wait for the profile query to load before connecting — otherwise all\n // users fall back to 'default' and share a single cdecli-agent session.\n const accountId = accountUserId ?? 'default';\n\n // Track the previous channelId so we can reconnect when the user opens a new chat.\n const prevChannelIdRef = useRef<string | undefined>(channelId);\n\n const [connectMutation] = useGatewayConnectMutation();\n const [disconnectMutation] = useGatewayDisconnectMutation();\n const [createTokenMutation] = useCreateSecretApiTokenMutation();\n const [revealTokenMutation] = useRevealSecretApiTokenMutation();\n const {\n data: systemTokenData,\n loading: systemTokenLoading,\n refetch: refetchSystemToken,\n } = useGetUserSystemTokenQuery({\n skip: !isSelected,\n fetchPolicy: 'network-only',\n });\n\n /** True when the backend rejects createSecretApiToken because the user already has one. */\n const isAlreadyHasSystemTokenError = (err: unknown): boolean => {\n const message = err instanceof Error ? err.message : String(err ?? '');\n return /already have a system token/i.test(message);\n };\n\n const obtainSystemToken = useCallback(async (): Promise<string | null> => {\n try {\n let tokenId: string | null = systemTokenData?.getUserSystemToken?.id ?? null;\n\n /**\n * Race recovery: if the GetUserSystemToken query hasn't returned yet (or returned\n * stale data) we'll fall through to createSecretApiToken. The backend rejects that\n * with \"you already have a system token\" — catch it, refetch, and use the existing\n * token id instead of falling back to an unauthenticated connection.\n */\n if (!tokenId) {\n if (!orgName || !projectId) {\n const refetchResult = await refetchSystemToken().catch(() => null);\n tokenId = refetchResult?.data?.getUserSystemToken?.id ?? null;\n if (!tokenId) return null;\n } else {\n try {\n const { data: createData } = await createTokenMutation({\n variables: {\n input: {\n name: 'System Token',\n expiryInSeconds: 31536000,\n isSystemToken: true,\n environmentTagId: tagId,\n orgName: orgName || 'default',\n projectId: projectId || 'default',\n },\n },\n });\n tokenId = createData?.createSecretApiToken?.id ?? null;\n await refetchSystemToken();\n } catch (createErr) {\n if (!isAlreadyHasSystemTokenError(createErr)) throw createErr;\n const refetchResult = await refetchSystemToken().catch(() => null);\n tokenId = refetchResult?.data?.getUserSystemToken?.id ?? null;\n if (!tokenId) {\n console.warn(\n '[useCdecliAutoConnect] System token already exists but refetch returned no id; retrying',\n );\n return null;\n }\n }\n }\n }\n\n if (!tokenId) return null;\n\n const { data: revealData } = await revealTokenMutation({\n variables: { id: tokenId },\n });\n return (revealData?.revealSecretApiToken as string) || null;\n } catch (err) {\n console.error('[useCdecliAutoConnect] obtainSystemToken error:', err);\n return null;\n }\n }, [systemTokenData, createTokenMutation, revealTokenMutation, refetchSystemToken, orgName, projectId, tagId]);\n\n // Auto-connect when CDeCLI gateway is selected\n useEffect(() => {\n if (!isSelected) {\n // Reset when deselected, but don't disconnect — keep the session alive\n // so switching back is instant.\n connectingRef.current = false;\n return;\n }\n\n // Wait until the user profile has loaded so accountId is the real\n // user id instead of the 'default' fallback.\n if (prerequisitesLoading || !accountUserId) return;\n\n /**\n * Wait for the GetUserSystemToken query to resolve before we connect — otherwise we\n * race the network and try to create a duplicate token, which the backend rejects with\n * \"you already have a system token\" and we fall back to an unauthenticated session.\n */\n if (systemTokenLoading) return;\n\n /**\n * If we're already connected and just switching channels, the gateway needs a reconnect\n * (the session is bound server-side to chatId), but the user already had a working\n * connection. Skip flipping the visible status to 'connecting' so the toolbar pill\n * doesn't briefly show \"Checking...\" every time someone taps a history row.\n */\n let isSilentReconnect = false;\n if (connectedRef.current || connectingRef.current) {\n if (channelId && prevChannelIdRef.current !== channelId) {\n isSilentReconnect = connectedRef.current;\n prevChannelIdRef.current = channelId;\n connectedRef.current = false;\n } else {\n return;\n }\n }\n\n const doConnect = async () => {\n connectingRef.current = true;\n if (!isSilentReconnect) setStatus('connecting');\n setError(null);\n\n try {\n const endpoint = config.CDECLI_AGENT_ENDPOINT || 'https://cdecli-agent.cdebase.dev';\n const token = await obtainSystemToken();\n if (!token) {\n console.warn('[useCdecliAutoConnect] No system token, connecting without auth');\n }\n\n const { data } = await connectMutation({\n variables: {\n input: {\n channelType: CHANNEL_TYPE,\n accountId,\n options: {\n endpoint: endpoint.trim(),\n ...(token ? { token } : {}),\n ...(channelId ? { chatId: channelId } : {}),\n },\n },\n },\n });\n\n const result = data?.gatewayConnect as\n | ((typeof data)['gatewayConnect'] & { persistenceMode?: string })\n | undefined;\n console.log(\n '[useCdecliAutoConnect] connectMutation result (account=%s):',\n accountId,\n JSON.stringify(result),\n );\n if (result?.persistenceMode) {\n setPersistenceMode(result.persistenceMode as 'backend' | 'frontend');\n }\n if (result?.state === 'CONNECTED' || result?.connected) {\n setStatus('connected');\n connectedRef.current = true;\n } else if (result?.state === 'ERROR') {\n setStatus('error');\n setError(result.lastError ?? 'Failed to connect to CDeCLI agent');\n connectedRef.current = false;\n } else {\n // Assume connecting — the subscription will push the final state\n setStatus('connected');\n connectedRef.current = true;\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error('[useCdecliAutoConnect] connect error:', msg);\n setStatus('error');\n setError(msg);\n connectedRef.current = false;\n } finally {\n connectingRef.current = false;\n }\n };\n\n doConnect();\n }, [\n isSelected,\n obtainSystemToken,\n connectMutation,\n accountId,\n prerequisitesLoading,\n accountUserId,\n channelId,\n systemTokenLoading,\n ]);\n\n // Keep the backend session alive across page refreshes and SPA navigations.\n // The backend CdecliServeProvider.connect() will reuse the existing session\n // if the endpoint hasn't changed, preserving conversation context.\n // Only disconnect when the user explicitly switches to a different gateway.\n\n /** Reconnect the CDeCLI session with a specific skill pre-activated. */\n const connectWithSkill = useCallback(\n async (skill: string, model?: string, systemPrompt?: string, skillId?: string) => {\n console.log(\n '[useCdecliAutoConnect] connectWithSkill called with skill=%s skillId=%s model=%s systemPrompt=%d chars',\n skill,\n skillId ?? '',\n model,\n systemPrompt?.length ?? 0,\n );\n setStatus('connecting');\n setError(null);\n\n try {\n const endpoint = config.CDECLI_AGENT_ENDPOINT || 'https://cdecli-agent.cdebase.dev';\n const token = await obtainSystemToken();\n\n console.log('[useCdecliAutoConnect] connectWithSkill sending mutation with skill=%s', skill);\n const { data } = await connectMutation({\n variables: {\n input: {\n channelType: CHANNEL_TYPE,\n accountId,\n options: {\n endpoint: endpoint.trim(),\n ...(token ? { token } : {}),\n skill,\n ...(skillId ? { skillId } : {}),\n ...(model ? { model } : {}),\n ...(systemPrompt ? { systemPrompt } : {}),\n ...(channelId ? { chatId: channelId } : {}),\n },\n },\n },\n });\n\n console.log('[useCdecliAutoConnect] connectWithSkill result:', JSON.stringify(data?.gatewayConnect));\n const result = data?.gatewayConnect as\n | ((typeof data)['gatewayConnect'] & { persistenceMode?: string })\n | undefined;\n if (result?.persistenceMode) {\n setPersistenceMode(result.persistenceMode as 'backend' | 'frontend');\n }\n if (result?.state === 'CONNECTED' || result?.connected) {\n setStatus('connected');\n connectedRef.current = true;\n setActiveSkill(skill);\n } else {\n setStatus('connected');\n connectedRef.current = true;\n setActiveSkill(skill);\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error('[useCdecliAutoConnect] connectWithSkill error:', msg);\n setStatus('error');\n setError(msg);\n }\n },\n [connectMutation, obtainSystemToken, accountId, channelId],\n );\n\n return {\n channelConnected: status === 'connected',\n status,\n error,\n persistenceMode,\n activeSkill,\n accountId,\n connectWithSkill,\n };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAkCA,MAAM,YAAe,GAAA,cAAA;AAQL,SAAA,oBAAA,CAAqB,YAAqB,SAAgD,EAAA;AACxG,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAI,SAAkC,MAAM,CAAA;AACpE,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAI,SAAwB,IAAI,CAAA;AACtD,EAAA,MAAM,CAAC,eAAA,EAAiB,kBAAkB,CAAA,GAAI,SAA6C,MAAS,CAAA;AACpG,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,SAAwB,IAAI,CAAA;AAClE,EAAM,MAAA,aAAA,GAAgB,OAAO,KAAK,CAAA;AAClC,EAAM,MAAA,YAAA,GAAe,OAAO,KAAK,CAAA;AACjC,EAAM,MAAA;AAAA,IACJ,OAAA;AAAA,IACA,SAAA;AAAA,IACA,KAAA;AAAA,IACA,aAAA;AAAA,IACA,OAAS,EAAA;AAAA,MACP,kBAAmB,EAAA;AAKvB,EAAA,MAAM,YAAY,aAAiB,IAAA,IAAA,GAAA,aAAA,GAAA,SAAA;AAGnC,EAAM,MAAA,gBAAA,GAAmB,OAA2B,SAAS,CAAA;AAC7D,EAAM,MAAA,CAAC,eAAe,CAAA,GAAI,yBAA0B,EAAA;AACpD,EAAM,MAAA,CAAC,kBAAkB,CAAA,GAAI,4BAA6B,EAAA;AAC1D,EAAM,MAAA,CAAC,mBAAmB,CAAA,GAAI,+BAAgC,EAAA;AAC9D,EAAM,MAAA,CAAC,mBAAmB,CAAA,GAAI,+BAAgC,EAAA;AAC9D,EAAM,MAAA;AAAA,IACJ,IAAM,EAAA,eAAA;AAAA,IACN,OAAS,EAAA,kBAAA;AAAA,IACT,OAAS,EAAA;AAAA,MACP,0BAA2B,CAAA;AAAA,IAC7B,MAAM,CAAC,UAAA;AAAA,IACP,WAAa,EAAA;AAAA,GACd,CAAA;AAGD,EAAM,MAAA,4BAAA,GAA+B,CAAC,GAA0B,KAAA;AAC9D,IAAA,MAAM,UAAU,GAAe,YAAA,KAAA,GAAQ,IAAI,OAAU,GAAA,MAAA,CAAO,oBAAO,EAAE,CAAA;AACrE,IAAO,OAAA,8BAAA,CAA+B,KAAK,OAAO,CAAA;AAAA,GACpD;AACA,EAAM,MAAA,iBAAA,GAAoB,YAAY,YAAoC;AAlF5E,IAAA,IAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA,EAAA;AAmFI,IAAI,IAAA;AACF,MAAA,IAAI,OAAyB,GAAA,CAAA,EAAA,GAAA,CAAA,EAAA,GAAA,eAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,eAAA,CAAiB,kBAAjB,KAAA,IAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAqC,OAArC,IAA2C,GAAA,EAAA,GAAA,IAAA;AAQxE,MAAA,IAAI,CAAC,OAAS,EAAA;AACZ,QAAI,IAAA,CAAC,OAAW,IAAA,CAAC,SAAW,EAAA;AAC1B,UAAA,MAAM,gBAAgB,MAAM,kBAAA,EAAqB,CAAA,KAAA,CAAM,MAAM,IAAI,CAAA;AACjE,UAAA,OAAA,GAAA,CAAU,gEAAe,IAAf,KAAA,IAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAqB,kBAArB,KAAA,IAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAyC,OAAzC,IAA+C,GAAA,EAAA,GAAA,IAAA;AACzD,UAAI,IAAA,CAAC,SAAgB,OAAA,IAAA;AAAA,SAChB,MAAA;AACL,UAAI,IAAA;AACF,YAAM,MAAA;AAAA,cACJ,IAAM,EAAA;AAAA,aACR,GAAI,MAAM,mBAAoB,CAAA;AAAA,cAC5B,SAAW,EAAA;AAAA,gBACT,KAAO,EAAA;AAAA,kBACL,IAAM,EAAA,cAAA;AAAA,kBACN,eAAiB,EAAA,OAAA;AAAA,kBACjB,aAAe,EAAA,IAAA;AAAA,kBACf,gBAAkB,EAAA,KAAA;AAAA,kBAClB,SAAS,OAAW,IAAA,SAAA;AAAA,kBACpB,WAAW,SAAa,IAAA;AAAA;AAC1B;AACF,aACD,CAAA;AACD,YAAA,OAAA,GAAA,CAAU,EAAY,GAAA,CAAA,EAAA,GAAA,UAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,UAAA,CAAA,oBAAA,KAAZ,IAAkC,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,EAAA,KAAlC,IAAwC,GAAA,EAAA,GAAA,IAAA;AAClD,YAAA,MAAM,kBAAmB,EAAA;AAAA,mBAClB,SAAW,EAAA;AAClB,YAAA,IAAI,CAAC,4BAAA,CAA6B,SAAS,CAAA,EAAS,MAAA,SAAA;AACpD,YAAA,MAAM,gBAAgB,MAAM,kBAAA,EAAqB,CAAA,KAAA,CAAM,MAAM,IAAI,CAAA;AACjE,YAAA,OAAA,GAAA,CAAU,gEAAe,IAAf,KAAA,IAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAqB,kBAArB,KAAA,IAAA,GAAA,KAAA,CAAA,GAAA,EAAA,CAAyC,OAAzC,IAA+C,GAAA,EAAA,GAAA,IAAA;AACzD,YAAA,IAAI,CAAC,OAAS,EAAA;AACZ,cAAA,OAAA,CAAQ,KAAK,yFAAyF,CAAA;AACtG,cAAO,OAAA,IAAA;AAAA;AACT;AACF;AACF;AAEF,MAAI,IAAA,CAAC,SAAgB,OAAA,IAAA;AACrB,MAAM,MAAA;AAAA,QACJ,IAAM,EAAA;AAAA,OACR,GAAI,MAAM,mBAAoB,CAAA;AAAA,QAC5B,SAAW,EAAA;AAAA,UACT,EAAI,EAAA;AAAA;AACN,OACD,CAAA;AACD,MAAA,OAAA,CAAO,yCAAY,oBAAkC,KAAA,IAAA;AAAA,aAC9C,GAAK,EAAA;AACZ,MAAQ,OAAA,CAAA,KAAA,CAAM,mDAAmD,GAAG,CAAA;AACpE,MAAO,OAAA,IAAA;AAAA;AACT,GACF,EAAG,CAAC,eAAiB,EAAA,mBAAA,EAAqB,qBAAqB,kBAAoB,EAAA,OAAA,EAAS,SAAW,EAAA,KAAK,CAAC,CAAA;AAG7G,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,CAAC,UAAY,EAAA;AAGf,MAAA,aAAA,CAAc,OAAU,GAAA,KAAA;AACxB,MAAA;AAAA;AAKF,IAAI,IAAA,oBAAA,IAAwB,CAAC,aAAe,EAAA;AAO5C,IAAA,IAAI,kBAAoB,EAAA;AAQxB,IAAA,IAAI,iBAAoB,GAAA,KAAA;AACxB,IAAI,IAAA,YAAA,CAAa,OAAW,IAAA,aAAA,CAAc,OAAS,EAAA;AACjD,MAAI,IAAA,SAAA,IAAa,gBAAiB,CAAA,OAAA,KAAY,SAAW,EAAA;AACvD,QAAA,iBAAA,GAAoB,YAAa,CAAA,OAAA;AACjC,QAAA,gBAAA,CAAiB,OAAU,GAAA,SAAA;AAC3B,QAAA,YAAA,CAAa,OAAU,GAAA,KAAA;AAAA,OAClB,MAAA;AACL,QAAA;AAAA;AACF;AAEF,IAAA,MAAM,YAAY,YAAY;AAjLlC,MAAA,IAAA,EAAA;AAkLM,MAAA,aAAA,CAAc,OAAU,GAAA,IAAA;AACxB,MAAI,IAAA,CAAC,iBAAmB,EAAA,SAAA,CAAU,YAAY,CAAA;AAC9C,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAI,IAAA;AACF,QAAM,MAAA,QAAA,GAAW,OAAO,qBAAyB,IAAA,kCAAA;AACjD,QAAM,MAAA,KAAA,GAAQ,MAAM,iBAAkB,EAAA;AACtC,QAAA,IAAI,CAAC,KAAO,EAAA;AACV,UAAA,OAAA,CAAQ,KAAK,iEAAiE,CAAA;AAAA;AAEhF,QAAM,MAAA;AAAA,UACJ;AAAA,SACF,GAAI,MAAM,eAAgB,CAAA;AAAA,UACxB,SAAW,EAAA;AAAA,YACT,KAAO,EAAA;AAAA,cACL,WAAa,EAAA,YAAA;AAAA,cACb,SAAA;AAAA,cACA,OAAS,EAAA,cAAA,CAAA,cAAA,CAAA;AAAA,gBACP,QAAA,EAAU,SAAS,IAAK;AAAA,eAAA,EACpB,KAAQ,GAAA;AAAA,gBACV;AAAA,eACF,GAAI,EAAC,CAAA,EACD,SAAY,GAAA;AAAA,gBACd,MAAQ,EAAA;AAAA,kBACN,EAAC;AAAA;AAET;AACF,SACD,CAAA;AACD,QAAA,MAAM,SAAS,IAAM,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,IAAA,CAAA,cAAA;AAGrB,QAAA,OAAA,CAAQ,IAAI,6DAA+D,EAAA,SAAA,EAAW,IAAK,CAAA,SAAA,CAAU,MAAM,CAAC,CAAA;AAC5G,QAAA,IAAI,iCAAQ,eAAiB,EAAA;AAC3B,UAAA,kBAAA,CAAmB,OAAO,eAAyC,CAAA;AAAA;AAErE,QAAA,IAAA,CAAI,MAAQ,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,MAAA,CAAA,KAAA,MAAU,WAAe,KAAA,MAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,MAAA,CAAQ,SAAW,CAAA,EAAA;AACtD,UAAA,SAAA,CAAU,WAAW,CAAA;AACrB,UAAA,YAAA,CAAa,OAAU,GAAA,IAAA;AAAA,SACzB,MAAA,IAAA,CAAW,MAAQ,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,MAAA,CAAA,KAAA,MAAU,OAAS,EAAA;AACpC,UAAA,SAAA,CAAU,OAAO,CAAA;AACjB,UAAS,QAAA,CAAA,CAAA,EAAA,GAAA,MAAA,CAAO,SAAP,KAAA,IAAA,GAAA,EAAA,GAAoB,mCAAmC,CAAA;AAChE,UAAA,YAAA,CAAa,OAAU,GAAA,KAAA;AAAA,SAClB,MAAA;AAEL,UAAA,SAAA,CAAU,WAAW,CAAA;AACrB,UAAA,YAAA,CAAa,OAAU,GAAA,IAAA;AAAA;AACzB,eACO,GAAK,EAAA;AACZ,QAAA,MAAM,MAAM,GAAe,YAAA,KAAA,GAAQ,GAAI,CAAA,OAAA,GAAU,OAAO,GAAG,CAAA;AAC3D,QAAQ,OAAA,CAAA,KAAA,CAAM,yCAAyC,GAAG,CAAA;AAC1D,QAAA,SAAA,CAAU,OAAO,CAAA;AACjB,QAAA,QAAA,CAAS,GAAG,CAAA;AACZ,QAAA,YAAA,CAAa,OAAU,GAAA,KAAA;AAAA,OACvB,SAAA;AACA,QAAA,aAAA,CAAc,OAAU,GAAA,KAAA;AAAA;AAC1B,KACF;AACA,IAAU,SAAA,EAAA;AAAA,GACZ,EAAG,CAAC,UAAA,EAAY,iBAAmB,EAAA,eAAA,EAAiB,WAAW,oBAAsB,EAAA,aAAA,EAAe,SAAW,EAAA,kBAAkB,CAAC,CAAA;AAQlI,EAAA,MAAM,mBAAmB,WAAY,CAAA,OAAO,KAAe,EAAA,KAAA,EAAgB,cAAuB,OAAqB,KAAA;AApPzH,IAAA,IAAA,EAAA;AAqPI,IAAQ,OAAA,CAAA,GAAA,CAAI,0GAA0G,KAAO,EAAA,OAAA,IAAA,IAAA,GAAA,OAAA,GAAW,IAAI,KAAO,EAAA,CAAA,EAAA,GAAA,YAAA,IAAA,IAAA,GAAA,MAAA,GAAA,YAAA,CAAc,MAAd,KAAA,IAAA,GAAA,EAAA,GAAwB,CAAC,CAAA;AAC5K,IAAA,SAAA,CAAU,YAAY,CAAA;AACtB,IAAA,QAAA,CAAS,IAAI,CAAA;AACb,IAAI,IAAA;AACF,MAAM,MAAA,QAAA,GAAW,OAAO,qBAAyB,IAAA,kCAAA;AACjD,MAAM,MAAA,KAAA,GAAQ,MAAM,iBAAkB,EAAA;AACtC,MAAQ,OAAA,CAAA,GAAA,CAAI,0EAA0E,KAAK,CAAA;AAC3F,MAAM,MAAA;AAAA,QACJ;AAAA,OACF,GAAI,MAAM,eAAgB,CAAA;AAAA,QACxB,SAAW,EAAA;AAAA,UACT,KAAO,EAAA;AAAA,YACL,WAAa,EAAA,YAAA;AAAA,YACb,SAAA;AAAA,YACA,OAAS,EAAA,cAAA,CAAA,cAAA,CAAA,cAAA,CAAA,cAAA,CAAA,aAAA,CAAA,cAAA,CAAA;AAAA,cACP,QAAA,EAAU,SAAS,IAAK;AAAA,aAAA,EACpB,KAAQ,GAAA;AAAA,cACV;AAAA,aACF,GAAI,EAJG,CAAA,EAAA;AAAA,cAKP;AAAA,aAAA,CAAA,EACI,OAAU,GAAA;AAAA,cACZ;AAAA,aACF,GAAI,EAAC,CAAA,EACD,KAAQ,GAAA;AAAA,cACV;AAAA,aACF,GAAI,EAAC,CAAA,EACD,YAAe,GAAA;AAAA,cACjB;AAAA,aACF,GAAI,EAAC,CAAA,EACD,SAAY,GAAA;AAAA,cACd,MAAQ,EAAA;AAAA,gBACN,EAAC;AAAA;AAET;AACF,OACD,CAAA;AACD,MAAA,OAAA,CAAQ,IAAI,iDAAmD,EAAA,IAAA,CAAK,SAAU,CAAA,IAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,IAAA,CAAM,cAAc,CAAC,CAAA;AACnG,MAAA,MAAM,SAAS,IAAM,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,IAAA,CAAA,cAAA;AAGrB,MAAA,IAAI,iCAAQ,eAAiB,EAAA;AAC3B,QAAA,kBAAA,CAAmB,OAAO,eAAyC,CAAA;AAAA;AAErE,MAAA,IAAA,CAAI,MAAQ,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,MAAA,CAAA,KAAA,MAAU,WAAe,KAAA,MAAA,IAAA,IAAA,GAAA,KAAA,CAAA,GAAA,MAAA,CAAQ,SAAW,CAAA,EAAA;AACtD,QAAA,SAAA,CAAU,WAAW,CAAA;AACrB,QAAA,YAAA,CAAa,OAAU,GAAA,IAAA;AACvB,QAAA,cAAA,CAAe,KAAK,CAAA;AAAA,OACf,MAAA;AACL,QAAA,SAAA,CAAU,WAAW,CAAA;AACrB,QAAA,YAAA,CAAa,OAAU,GAAA,IAAA;AACvB,QAAA,cAAA,CAAe,KAAK,CAAA;AAAA;AACtB,aACO,GAAK,EAAA;AACZ,MAAA,MAAM,MAAM,GAAe,YAAA,KAAA,GAAQ,GAAI,CAAA,OAAA,GAAU,OAAO,GAAG,CAAA;AAC3D,MAAQ,OAAA,CAAA,KAAA,CAAM,kDAAkD,GAAG,CAAA;AACnE,MAAA,SAAA,CAAU,OAAO,CAAA;AACjB,MAAA,QAAA,CAAS,GAAG,CAAA;AAAA;AACd,KACC,CAAC,eAAA,EAAiB,iBAAmB,EAAA,SAAA,EAAW,SAAS,CAAC,CAAA;AAC7D,EAAO,OAAA;AAAA,IACL,kBAAkB,MAAW,KAAA,WAAA;AAAA,IAC7B,MAAA;AAAA,IACA,KAAA;AAAA,IACA,eAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GACF;AACF"}
|
|
1
|
+
{"version":3,"file":"useCdecliAutoConnect.js","sources":["../../src/hooks/useCdecliAutoConnect.ts"],"sourcesContent":["/**\n * Auto-connects the cdecli-serve messenger-gateway channel when the CDeCLI\n * gateway is selected from the dropdown. Obtains/creates a system token and\n * calls the `gatewayConnect` mutation so the backend provider has a live\n * session with the cdecli-agent endpoint.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport {\n useGatewayConnectMutation,\n useGatewayDisconnectMutation,\n useGetUserSystemTokenQuery,\n useCreateSecretApiTokenMutation,\n useRevealSecretApiTokenMutation,\n} from 'common/graphql';\nimport { SecretApiTokenAlgorithm } from 'common';\nimport { config } from '../config/env-config';\nimport { usePrerequisiteIds } from './usePrerequisiteIds';\n\n/** Local backend ships RS256 public key but often no private key; HS256 uses dev JWT secret. */\nconst SYSTEM_TOKEN_ALGORITHM = __DEV__ ? SecretApiTokenAlgorithm.Hs256 : SecretApiTokenAlgorithm.Rs256;\n\n// ─── Types ───────────────────────────────────────────────────────\n\nexport type CdecliAutoConnectStatus = 'idle' | 'connecting' | 'connected' | 'error';\n\nexport interface UseCdecliAutoConnectResult {\n /** Whether the backend cdecli-serve channel is connected. */\n channelConnected: boolean;\n /** Current connection status. */\n status: CdecliAutoConnectStatus;\n /** Error message if status is 'error'. */\n error: string | null;\n /** Persistence mode reported by the backend provider ('backend' | 'frontend'). */\n persistenceMode: 'backend' | 'frontend' | undefined;\n /** Active skill name on the current CDeCLI session (null if none). */\n activeSkill: string | null;\n /** Per-user accountId used for this gateway connection. */\n accountId: string;\n /** Reconnect the CDeCLI session with a specific skill pre-activated. */\n connectWithSkill: (skill: string, model?: string, systemPrompt?: string, skillId?: string) => Promise<void>;\n}\n\n// ─── Constants ───────────────────────────────────────────────────\n\nconst CHANNEL_TYPE = 'cdecli-serve';\n\n// ─── Hook ────────────────────────────────────────────────────────\n\n/**\n * When `isSelected` is true, auto-connects the cdecli-serve channel on the\n * messenger-gateway backend using the hosted endpoint and a system token.\n */\nexport function useCdecliAutoConnect(isSelected: boolean, channelId?: string): UseCdecliAutoConnectResult {\n const [status, setStatus] = useState<CdecliAutoConnectStatus>('idle');\n const [error, setError] = useState<string | null>(null);\n const [persistenceMode, setPersistenceMode] = useState<'backend' | 'frontend' | undefined>(undefined);\n const [activeSkill, setActiveSkill] = useState<string | null>(null);\n const connectingRef = useRef(false);\n const connectedRef = useRef(false);\n\n const { orgName, projectId, tagId, accountUserId, loading: prerequisitesLoading } = usePrerequisiteIds();\n\n // Per-user accountId so each user gets their own cdecli-agent session.\n // Wait for the profile query to load before connecting — otherwise all\n // users fall back to 'default' and share a single cdecli-agent session.\n const accountId = accountUserId ?? 'default';\n\n // Track the previous channelId so we can reconnect when the user opens a new chat.\n const prevChannelIdRef = useRef<string | undefined>(channelId);\n\n const [connectMutation] = useGatewayConnectMutation();\n const [disconnectMutation] = useGatewayDisconnectMutation();\n const [createTokenMutation] = useCreateSecretApiTokenMutation();\n const [revealTokenMutation] = useRevealSecretApiTokenMutation();\n const {\n data: systemTokenData,\n loading: systemTokenLoading,\n refetch: refetchSystemToken,\n } = useGetUserSystemTokenQuery({\n skip: !isSelected,\n fetchPolicy: 'network-only',\n });\n\n /** True when the backend rejects createSecretApiToken because the user already has one. */\n const isAlreadyHasSystemTokenError = (err: unknown): boolean => {\n const message = err instanceof Error ? err.message : String(err ?? '');\n return /already have a system token/i.test(message);\n };\n\n const obtainSystemToken = useCallback(async (): Promise<string | null> => {\n try {\n let tokenId: string | null = systemTokenData?.getUserSystemToken?.id ?? null;\n\n /**\n * Race recovery: if the GetUserSystemToken query hasn't returned yet (or returned\n * stale data) we'll fall through to createSecretApiToken. The backend rejects that\n * with \"you already have a system token\" — catch it, refetch, and use the existing\n * token id instead of falling back to an unauthenticated connection.\n */\n if (!tokenId) {\n if (!orgName || !projectId) {\n const refetchResult = await refetchSystemToken().catch(() => null);\n tokenId = refetchResult?.data?.getUserSystemToken?.id ?? null;\n if (!tokenId) return null;\n } else {\n try {\n const { data: createData } = await createTokenMutation({\n variables: {\n input: {\n name: 'System Token',\n expiryInSeconds: 31536000,\n isSystemToken: true,\n environmentTagId: tagId,\n orgName: orgName || 'default',\n projectId: projectId || 'default',\n algorithm: SYSTEM_TOKEN_ALGORITHM,\n },\n },\n });\n tokenId = createData?.createSecretApiToken?.id ?? null;\n await refetchSystemToken();\n } catch (createErr) {\n if (!isAlreadyHasSystemTokenError(createErr)) throw createErr;\n const refetchResult = await refetchSystemToken().catch(() => null);\n tokenId = refetchResult?.data?.getUserSystemToken?.id ?? null;\n if (!tokenId) {\n console.warn(\n '[useCdecliAutoConnect] System token already exists but refetch returned no id; retrying',\n );\n return null;\n }\n }\n }\n }\n\n if (!tokenId) return null;\n\n const { data: revealData } = await revealTokenMutation({\n variables: { id: tokenId },\n });\n return (revealData?.revealSecretApiToken as string) || null;\n } catch (err) {\n console.error('[useCdecliAutoConnect] obtainSystemToken error:', err);\n return null;\n }\n }, [systemTokenData, createTokenMutation, revealTokenMutation, refetchSystemToken, orgName, projectId, tagId]);\n\n // Auto-connect when CDeCLI gateway is selected\n useEffect(() => {\n if (!isSelected) {\n // Reset when deselected, but don't disconnect — keep the session alive\n // so switching back is instant.\n connectingRef.current = false;\n return;\n }\n\n // Wait until the user profile has loaded so accountId is the real\n // user id instead of the 'default' fallback.\n if (prerequisitesLoading || !accountUserId) return;\n\n /**\n * Wait for the GetUserSystemToken query to resolve before we connect — otherwise we\n * race the network and try to create a duplicate token, which the backend rejects with\n * \"you already have a system token\" and we fall back to an unauthenticated session.\n */\n if (systemTokenLoading) return;\n\n /**\n * If we're already connected and just switching channels, the gateway needs a reconnect\n * (the session is bound server-side to chatId), but the user already had a working\n * connection. Skip flipping the visible status to 'connecting' so the toolbar pill\n * doesn't briefly show \"Checking...\" every time someone taps a history row.\n */\n let isSilentReconnect = false;\n if (connectedRef.current || connectingRef.current) {\n if (channelId && prevChannelIdRef.current !== channelId) {\n isSilentReconnect = connectedRef.current;\n prevChannelIdRef.current = channelId;\n connectedRef.current = false;\n } else {\n return;\n }\n }\n\n const doConnect = async () => {\n connectingRef.current = true;\n if (!isSilentReconnect) setStatus('connecting');\n setError(null);\n\n try {\n const endpoint = config.CDECLI_AGENT_ENDPOINT || 'https://cdecli-agent.cdebase.dev';\n const token = await obtainSystemToken();\n if (!token) {\n console.warn('[useCdecliAutoConnect] No system token, connecting without auth');\n }\n\n const { data } = await connectMutation({\n variables: {\n input: {\n channelType: CHANNEL_TYPE,\n accountId,\n options: {\n endpoint: endpoint.trim(),\n ...(token ? { token } : {}),\n ...(channelId ? { chatId: channelId } : {}),\n },\n },\n },\n });\n\n const result = data?.gatewayConnect as\n | ((typeof data)['gatewayConnect'] & { persistenceMode?: string })\n | undefined;\n console.log(\n '[useCdecliAutoConnect] connectMutation result (account=%s):',\n accountId,\n JSON.stringify(result),\n );\n if (result?.persistenceMode) {\n setPersistenceMode(result.persistenceMode as 'backend' | 'frontend');\n }\n if (result?.state === 'CONNECTED' || result?.connected) {\n setStatus('connected');\n connectedRef.current = true;\n } else if (result?.state === 'ERROR') {\n setStatus('error');\n setError(result.lastError ?? 'Failed to connect to CDeCLI agent');\n connectedRef.current = false;\n } else {\n // Assume connecting — the subscription will push the final state\n setStatus('connected');\n connectedRef.current = true;\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error('[useCdecliAutoConnect] connect error:', msg);\n setStatus('error');\n setError(msg);\n connectedRef.current = false;\n } finally {\n connectingRef.current = false;\n }\n };\n\n doConnect();\n }, [\n isSelected,\n obtainSystemToken,\n connectMutation,\n accountId,\n prerequisitesLoading,\n accountUserId,\n channelId,\n systemTokenLoading,\n ]);\n\n // Keep the backend session alive across page refreshes and SPA navigations.\n // The backend CdecliServeProvider.connect() will reuse the existing session\n // if the endpoint hasn't changed, preserving conversation context.\n // Only disconnect when the user explicitly switches to a different gateway.\n\n /** Reconnect the CDeCLI session with a specific skill pre-activated. */\n const connectWithSkill = useCallback(\n async (skill: string, model?: string, systemPrompt?: string, skillId?: string) => {\n console.log(\n '[useCdecliAutoConnect] connectWithSkill called with skill=%s skillId=%s model=%s systemPrompt=%d chars',\n skill,\n skillId ?? '',\n model,\n systemPrompt?.length ?? 0,\n );\n setStatus('connecting');\n setError(null);\n\n try {\n const endpoint = config.CDECLI_AGENT_ENDPOINT || 'https://cdecli-agent.cdebase.dev';\n const token = await obtainSystemToken();\n\n console.log('[useCdecliAutoConnect] connectWithSkill sending mutation with skill=%s', skill);\n const { data } = await connectMutation({\n variables: {\n input: {\n channelType: CHANNEL_TYPE,\n accountId,\n options: {\n endpoint: endpoint.trim(),\n ...(token ? { token } : {}),\n skill,\n ...(skillId ? { skillId } : {}),\n ...(model ? { model } : {}),\n ...(systemPrompt ? { systemPrompt } : {}),\n ...(channelId ? { chatId: channelId } : {}),\n },\n },\n },\n });\n\n console.log('[useCdecliAutoConnect] connectWithSkill result:', JSON.stringify(data?.gatewayConnect));\n const result = data?.gatewayConnect as\n | ((typeof data)['gatewayConnect'] & { persistenceMode?: string })\n | undefined;\n if (result?.persistenceMode) {\n setPersistenceMode(result.persistenceMode as 'backend' | 'frontend');\n }\n if (result?.state === 'CONNECTED' || result?.connected) {\n setStatus('connected');\n connectedRef.current = true;\n setActiveSkill(skill);\n } else {\n setStatus('connected');\n connectedRef.current = true;\n setActiveSkill(skill);\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n console.error('[useCdecliAutoConnect] connectWithSkill error:', msg);\n setStatus('error');\n setError(msg);\n }\n },\n [connectMutation, obtainSystemToken, accountId, channelId],\n );\n\n return {\n channelConnected: status === 'connected',\n status,\n error,\n persistenceMode,\n activeSkill,\n accountId,\n connectWithSkill,\n };\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {useRef,useCallback,useEffect}from'react';import {useGatewaySendMessageMutation,useMessengerStreamDeltaSubscription,useGatewayInboundMessageByChannelSubscription}from'common/graphql';
|
|
1
|
+
import {useRef,useCallback,useEffect}from'react';import {useGatewaySendMessageMutation,useMessengerStreamDeltaSubscription,useGatewayInboundMessageByChannelSubscription}from'common/graphql';var __defProp = Object.defineProperty;
|
|
2
2
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
3
3
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
4
4
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
@@ -14,23 +14,20 @@ var __spreadValues = (a, b) => {
|
|
|
14
14
|
}
|
|
15
15
|
return a;
|
|
16
16
|
};
|
|
17
|
-
const CDECLI_RESPONSE_WAIT_MS = config.CDECLI_CHAT_RESPONSE_TIMEOUT_SEC * 1e3;
|
|
18
17
|
function stripModelCostHeader(content) {
|
|
19
18
|
const normalized = content.replace(/\r\n/g, "\n");
|
|
20
19
|
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, "");
|
|
21
20
|
}
|
|
22
|
-
|
|
21
|
+
const CDECLI_RESPONSE_TIMEOUT_MS = 12e4;
|
|
22
|
+
function useCdecliChannel(isConnected, accountId, channelId, callbacks, model, skill) {
|
|
23
23
|
const [sendMutation] = useGatewaySendMessageMutation();
|
|
24
24
|
const cbRef = useRef(callbacks);
|
|
25
25
|
cbRef.current = callbacks;
|
|
26
26
|
const pendingRef = useRef(null);
|
|
27
|
-
const sendNonceSeqRef = useRef(0);
|
|
28
|
-
const lastInboundNonceHandledRef = useRef(0);
|
|
29
27
|
const hasReceivedDeltasRef = useRef(false);
|
|
30
28
|
const reconnectedStreamRef = useRef(false);
|
|
31
29
|
const streamCompletedRef = useRef(false);
|
|
32
30
|
const accumulatedLenRef = useRef(0);
|
|
33
|
-
const lastAccumulatedFullTextRef = useRef("");
|
|
34
31
|
const timeoutRef = useRef(null);
|
|
35
32
|
const streamSkip = !channelId;
|
|
36
33
|
const streamChannelId = channelId || accountId;
|
|
@@ -38,47 +35,14 @@ function useCdecliChannel(enabled, isConnected, accountId, channelId, callbacks,
|
|
|
38
35
|
variables: {
|
|
39
36
|
channelId: streamChannelId
|
|
40
37
|
},
|
|
41
|
-
skip:
|
|
38
|
+
skip: streamSkip,
|
|
42
39
|
onData: ({
|
|
43
40
|
data
|
|
44
41
|
}) => {
|
|
45
|
-
var _a, _b
|
|
42
|
+
var _a, _b;
|
|
46
43
|
const delta = (_a = data == null ? void 0 : data.data) == null ? void 0 : _a.messengerStreamDelta;
|
|
47
44
|
if (!delta) return;
|
|
48
|
-
if (delta.isFinal)
|
|
49
|
-
if (streamCompletedRef.current) return;
|
|
50
|
-
const fromDelta = stripModelCostHeader((_b = delta.text) != null ? _b : "");
|
|
51
|
-
const fullText2 = fromDelta.trim().length > 0 ? fromDelta : lastAccumulatedFullTextRef.current;
|
|
52
|
-
if (!fullText2.trim()) {
|
|
53
|
-
if (pendingRef.current) {
|
|
54
|
-
streamCompletedRef.current = true;
|
|
55
|
-
cbRef.current.onError("CDeCLI returned an empty response.");
|
|
56
|
-
pendingRef.current = null;
|
|
57
|
-
hasReceivedDeltasRef.current = false;
|
|
58
|
-
lastAccumulatedFullTextRef.current = "";
|
|
59
|
-
if (timeoutRef.current) {
|
|
60
|
-
clearTimeout(timeoutRef.current);
|
|
61
|
-
timeoutRef.current = null;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
streamCompletedRef.current = true;
|
|
67
|
-
if (!hasReceivedDeltasRef.current) {
|
|
68
|
-
cbRef.current.onChunk(fullText2);
|
|
69
|
-
}
|
|
70
|
-
cbRef.current.onComplete(fullText2);
|
|
71
|
-
pendingRef.current = null;
|
|
72
|
-
hasReceivedDeltasRef.current = false;
|
|
73
|
-
reconnectedStreamRef.current = false;
|
|
74
|
-
accumulatedLenRef.current = 0;
|
|
75
|
-
lastAccumulatedFullTextRef.current = "";
|
|
76
|
-
if (timeoutRef.current) {
|
|
77
|
-
clearTimeout(timeoutRef.current);
|
|
78
|
-
timeoutRef.current = null;
|
|
79
|
-
}
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
45
|
+
if (delta.isFinal) return;
|
|
82
46
|
if (streamCompletedRef.current) return;
|
|
83
47
|
if (!pendingRef.current) {
|
|
84
48
|
if (!reconnectedStreamRef.current) {
|
|
@@ -87,8 +51,7 @@ function useCdecliChannel(enabled, isConnected, accountId, channelId, callbacks,
|
|
|
87
51
|
}
|
|
88
52
|
}
|
|
89
53
|
hasReceivedDeltasRef.current = true;
|
|
90
|
-
const fullText = stripModelCostHeader((
|
|
91
|
-
lastAccumulatedFullTextRef.current = fullText;
|
|
54
|
+
const fullText = stripModelCostHeader((_b = delta.text) != null ? _b : "");
|
|
92
55
|
const newChunk = fullText.substring(accumulatedLenRef.current);
|
|
93
56
|
accumulatedLenRef.current = fullText.length;
|
|
94
57
|
if (newChunk) {
|
|
@@ -103,46 +66,23 @@ function useCdecliChannel(enabled, isConnected, accountId, channelId, callbacks,
|
|
|
103
66
|
variables: {
|
|
104
67
|
channelId: streamChannelId
|
|
105
68
|
},
|
|
106
|
-
skip: !
|
|
69
|
+
skip: !isConnected || streamSkip,
|
|
107
70
|
onData: ({
|
|
108
71
|
data
|
|
109
72
|
}) => {
|
|
110
|
-
var _a
|
|
73
|
+
var _a;
|
|
111
74
|
const msg = (_a = data == null ? void 0 : data.data) == null ? void 0 : _a.gatewayInboundMessageByChannel;
|
|
112
|
-
if (!msg) return;
|
|
113
|
-
const
|
|
114
|
-
const nonce = pending == null ? void 0 : pending.nonce;
|
|
115
|
-
if (nonce == null) return;
|
|
116
|
-
if (lastInboundNonceHandledRef.current === nonce) {
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
lastInboundNonceHandledRef.current = nonce;
|
|
120
|
-
const sanitizedText = stripModelCostHeader((_b = msg.text) != null ? _b : "");
|
|
121
|
-
const effectiveText = sanitizedText.trim().length > 0 ? sanitizedText : lastAccumulatedFullTextRef.current;
|
|
122
|
-
if (!effectiveText.trim()) {
|
|
123
|
-
if (pendingRef.current) {
|
|
124
|
-
streamCompletedRef.current = true;
|
|
125
|
-
cbRef.current.onError("CDeCLI returned an empty response.");
|
|
126
|
-
pendingRef.current = null;
|
|
127
|
-
hasReceivedDeltasRef.current = false;
|
|
128
|
-
lastAccumulatedFullTextRef.current = "";
|
|
129
|
-
if (timeoutRef.current) {
|
|
130
|
-
clearTimeout(timeoutRef.current);
|
|
131
|
-
timeoutRef.current = null;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
75
|
+
if (!(msg == null ? void 0 : msg.text)) return;
|
|
76
|
+
const sanitizedText = stripModelCostHeader(msg.text);
|
|
136
77
|
if (!hasReceivedDeltasRef.current) {
|
|
137
|
-
cbRef.current.onChunk(
|
|
78
|
+
cbRef.current.onChunk(sanitizedText);
|
|
138
79
|
}
|
|
139
|
-
cbRef.current.onComplete(
|
|
80
|
+
cbRef.current.onComplete(sanitizedText);
|
|
140
81
|
pendingRef.current = null;
|
|
141
82
|
hasReceivedDeltasRef.current = false;
|
|
142
83
|
reconnectedStreamRef.current = false;
|
|
143
84
|
streamCompletedRef.current = true;
|
|
144
85
|
accumulatedLenRef.current = 0;
|
|
145
|
-
lastAccumulatedFullTextRef.current = "";
|
|
146
86
|
if (timeoutRef.current) {
|
|
147
87
|
clearTimeout(timeoutRef.current);
|
|
148
88
|
timeoutRef.current = null;
|
|
@@ -155,18 +95,15 @@ function useCdecliChannel(enabled, isConnected, accountId, channelId, callbacks,
|
|
|
155
95
|
});
|
|
156
96
|
const sendMessage = useCallback(async (text, chatId = "messenger") => {
|
|
157
97
|
var _a;
|
|
158
|
-
if (!
|
|
159
|
-
sendNonceSeqRef.current += 1;
|
|
98
|
+
if (!isConnected) return false;
|
|
160
99
|
pendingRef.current = {
|
|
161
100
|
text,
|
|
162
|
-
sentAt: Date.now()
|
|
163
|
-
nonce: sendNonceSeqRef.current
|
|
101
|
+
sentAt: Date.now()
|
|
164
102
|
};
|
|
165
103
|
hasReceivedDeltasRef.current = false;
|
|
166
104
|
reconnectedStreamRef.current = false;
|
|
167
105
|
streamCompletedRef.current = false;
|
|
168
106
|
accumulatedLenRef.current = 0;
|
|
169
|
-
lastAccumulatedFullTextRef.current = "";
|
|
170
107
|
try {
|
|
171
108
|
const result = await sendMutation({
|
|
172
109
|
variables: {
|
|
@@ -196,10 +133,9 @@ function useCdecliChannel(enabled, isConnected, accountId, channelId, callbacks,
|
|
|
196
133
|
pendingRef.current = null;
|
|
197
134
|
hasReceivedDeltasRef.current = false;
|
|
198
135
|
timeoutRef.current = null;
|
|
199
|
-
|
|
200
|
-
cbRef.current.onError(`CDeCLI agent did not respond within ${sec}s. Trying the backup chat provider\u2026`);
|
|
136
|
+
cbRef.current.onError("CDeCLI agent did not respond within 120 seconds. The query may still be processing.");
|
|
201
137
|
}
|
|
202
|
-
},
|
|
138
|
+
}, CDECLI_RESPONSE_TIMEOUT_MS);
|
|
203
139
|
return true;
|
|
204
140
|
} catch (err) {
|
|
205
141
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -207,14 +143,13 @@ function useCdecliChannel(enabled, isConnected, accountId, channelId, callbacks,
|
|
|
207
143
|
pendingRef.current = null;
|
|
208
144
|
return false;
|
|
209
145
|
}
|
|
210
|
-
}, [
|
|
146
|
+
}, [isConnected, accountId, channelId, sendMutation, model, skill]);
|
|
211
147
|
useEffect(() => () => {
|
|
212
148
|
pendingRef.current = null;
|
|
213
149
|
hasReceivedDeltasRef.current = false;
|
|
214
150
|
reconnectedStreamRef.current = false;
|
|
215
151
|
streamCompletedRef.current = false;
|
|
216
152
|
accumulatedLenRef.current = 0;
|
|
217
|
-
lastAccumulatedFullTextRef.current = "";
|
|
218
153
|
if (timeoutRef.current) {
|
|
219
154
|
clearTimeout(timeoutRef.current);
|
|
220
155
|
timeoutRef.current = null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCdecliChannel.js","sources":["../../src/hooks/useCdecliChannel.ts"],"sourcesContent":["/**\n * Wires cdecli-serve messenger-gateway into the mobile chat UI (same as account/browser).\n */\n\nimport { useCallback, useEffect, useRef } from 'react';\nimport {\n useGatewaySendMessageMutation,\n useGatewayInboundMessageByChannelSubscription,\n useMessengerStreamDeltaSubscription,\n} from 'common/graphql';\nimport { config } from '../config/env-config';\n\nconst CDECLI_RESPONSE_WAIT_MS = config.CDECLI_CHAT_RESPONSE_TIMEOUT_SEC * 1000;\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\nexport interface CdecliChannelCallbacks {\n onChunk: (text: string) => void;\n onComplete: (text: string) => void;\n onError: (error: string) => void;\n}\n\nexport function useCdecliChannel(\n /** When false, no WS subscriptions (e.g. Groq mode). */\n enabled: boolean,\n isConnected: boolean,\n accountId: string,\n channelId: string | undefined,\n callbacks: CdecliChannelCallbacks,\n model?: string,\n skill?: string,\n) {\n const [sendMutation] = useGatewaySendMessageMutation();\n const cbRef = useRef(callbacks);\n cbRef.current = callbacks;\n\n const pendingRef = useRef<{ text: string; sentAt: number; nonce: number } | null>(null);\n const sendNonceSeqRef = useRef(0);\n /** Dedupes duplicate inbound deliveries for the same outbound send (Apollo can invoke `onData` twice). */\n const lastInboundNonceHandledRef = useRef<number>(0);\n const hasReceivedDeltasRef = useRef(false);\n const reconnectedStreamRef = useRef(false);\n const streamCompletedRef = useRef(false);\n const accumulatedLenRef = useRef(0);\n /** Latest full accumulated assistant text from non-final deltas (for isFinal / empty inbound completion). */\n const lastAccumulatedFullTextRef = useRef('');\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const streamSkip = !channelId;\n const streamChannelId = channelId || accountId;\n\n useMessengerStreamDeltaSubscription({\n variables: { channelId: streamChannelId },\n skip: !enabled || streamSkip,\n onData: ({ data }) => {\n const delta = data?.data?.messengerStreamDelta;\n if (!delta) return;\n\n if (delta.isFinal) {\n if (streamCompletedRef.current) return;\n const fromDelta = stripModelCostHeader(delta.text ?? '');\n const fullText = fromDelta.trim().length > 0 ? fromDelta : lastAccumulatedFullTextRef.current;\n if (!fullText.trim()) {\n if (pendingRef.current) {\n streamCompletedRef.current = true;\n cbRef.current.onError('CDeCLI returned an empty response.');\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n lastAccumulatedFullTextRef.current = '';\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n }\n return;\n }\n\n streamCompletedRef.current = true;\n if (!hasReceivedDeltasRef.current) {\n cbRef.current.onChunk(fullText);\n }\n cbRef.current.onComplete(fullText);\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n accumulatedLenRef.current = 0;\n lastAccumulatedFullTextRef.current = '';\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n return;\n }\n\n if (streamCompletedRef.current) return;\n if (!pendingRef.current) {\n if (!reconnectedStreamRef.current) {\n reconnectedStreamRef.current = true;\n accumulatedLenRef.current = 0;\n }\n }\n hasReceivedDeltasRef.current = true;\n const fullText = stripModelCostHeader(delta.text ?? '');\n lastAccumulatedFullTextRef.current = fullText;\n const newChunk = fullText.substring(accumulatedLenRef.current);\n accumulatedLenRef.current = fullText.length;\n if (newChunk) {\n cbRef.current.onChunk(newChunk);\n }\n },\n onError: (err) => {\n console.error('[useCdecliChannel] stream delta subscription error:', err);\n },\n });\n\n useGatewayInboundMessageByChannelSubscription({\n variables: { channelId: streamChannelId },\n skip: !enabled || !isConnected || streamSkip,\n onData: ({ data }) => {\n const msg = data?.data?.gatewayInboundMessageByChannel;\n if (!msg) return;\n\n const pending = pendingRef.current;\n const nonce = pending?.nonce;\n if (nonce == null) return;\n if (lastInboundNonceHandledRef.current === nonce) {\n return;\n }\n lastInboundNonceHandledRef.current = nonce;\n\n const sanitizedText = stripModelCostHeader(msg.text ?? '');\n const effectiveText = sanitizedText.trim().length > 0 ? sanitizedText : lastAccumulatedFullTextRef.current;\n if (!effectiveText.trim()) {\n if (pendingRef.current) {\n streamCompletedRef.current = true;\n cbRef.current.onError('CDeCLI returned an empty response.');\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n lastAccumulatedFullTextRef.current = '';\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n }\n return;\n }\n\n if (!hasReceivedDeltasRef.current) {\n cbRef.current.onChunk(effectiveText);\n }\n cbRef.current.onComplete(effectiveText);\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = true;\n accumulatedLenRef.current = 0;\n lastAccumulatedFullTextRef.current = '';\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n },\n onError: (err) => {\n console.error('[useCdecliChannel] subscription error:', err);\n cbRef.current.onError(err.message || 'CDeCLI subscription error');\n },\n });\n\n const sendMessage = useCallback(\n async (text: string, chatId = 'messenger'): Promise<boolean> => {\n if (!enabled || !isConnected) return false;\n sendNonceSeqRef.current += 1;\n pendingRef.current = { text, sentAt: Date.now(), nonce: sendNonceSeqRef.current };\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = false;\n accumulatedLenRef.current = 0;\n lastAccumulatedFullTextRef.current = '';\n\n try {\n const result = await sendMutation({\n variables: {\n input: {\n channelType: 'cdecli-serve',\n accountId,\n chatId,\n text,\n ...(model || skill\n ? { metadata: { ...(model && { model }), ...(skill && { skill }) } }\n : {}),\n },\n },\n });\n\n const payload = result.data?.gatewaySendMessage;\n if (!payload?.success) {\n const errMsg = payload?.error || 'CDeCLI send failed';\n cbRef.current.onError(errMsg);\n pendingRef.current = null;\n return false;\n }\n\n timeoutRef.current = setTimeout(() => {\n if (pendingRef.current) {\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n timeoutRef.current = null;\n const sec = Math.round(CDECLI_RESPONSE_WAIT_MS / 1000);\n cbRef.current.onError(\n `CDeCLI agent did not respond within ${sec}s. Trying the backup chat provider…`,\n );\n }\n }, CDECLI_RESPONSE_WAIT_MS);\n\n return true;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n cbRef.current.onError(msg);\n pendingRef.current = null;\n return false;\n }\n },\n [enabled, isConnected, accountId, channelId, sendMutation, model, skill],\n );\n\n useEffect(\n () => () => {\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = false;\n accumulatedLenRef.current = 0;\n lastAccumulatedFullTextRef.current = '';\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n },\n [],\n );\n\n return { sendMessage };\n}\n"],"names":["fullText"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useCdecliChannel.js","sources":["../../src/hooks/useCdecliChannel.ts"],"sourcesContent":["/**\n * useCdecliChannel — wires the cdecli-serve messenger-gateway channel into the mobile chat UI.\n *\n * Kept in sync with `packages-modules/account/browser/src/hooks/useCdecliChannel.ts`.\n * When the CDeCLI channel is connected:\n * - `sendMessage(text)` calls `gatewaySendMessage`\n * - `MessengerStreamDelta` subscription delivers streaming chunks via `onChunk`\n * - `GatewayInboundMessageByChannel` delivers the final reply via `onComplete`\n */\n\nimport { useCallback, useEffect, useRef } from 'react';\nimport {\n useGatewaySendMessageMutation,\n useGatewayInboundMessageByChannelSubscription,\n useMessengerStreamDeltaSubscription,\n} from 'common/graphql';\n\nfunction stripModelCostHeader(content: string): string {\n const normalized = content.replace(/\\r\\n/g, '\\n');\n return normalized.replace(\n /^\\s*(?:[^\\w\\n]+\\s*)?[a-z0-9][a-z0-9._-]*\\s*\\(\\s*\\$[\\d.]+\\s*\\/\\s*MTok\\s+in\\s*\\)\\s*\\n+/i,\n '',\n );\n}\n\nexport interface CdecliChannelCallbacks {\n onChunk: (text: string) => void;\n onComplete: (text: string) => void;\n onError: (error: string) => void;\n}\n\n/** Same 120s window as web — deep CDeCLI queries can exceed 45s. */\nconst CDECLI_RESPONSE_TIMEOUT_MS = 120_000;\n\nexport function useCdecliChannel(\n isConnected: boolean,\n accountId: string,\n channelId: string | undefined,\n callbacks: CdecliChannelCallbacks,\n model?: string,\n skill?: string,\n) {\n const [sendMutation] = useGatewaySendMessageMutation();\n const cbRef = useRef(callbacks);\n cbRef.current = callbacks;\n\n const pendingRef = useRef<{ text: string; sentAt: number } | null>(null);\n const hasReceivedDeltasRef = useRef(false);\n const reconnectedStreamRef = useRef(false);\n const streamCompletedRef = useRef(false);\n const accumulatedLenRef = useRef(0);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const streamSkip = !channelId;\n const streamChannelId = channelId || accountId;\n\n useMessengerStreamDeltaSubscription({\n variables: { channelId: streamChannelId },\n skip: streamSkip,\n onData: ({ data }) => {\n const delta = data?.data?.messengerStreamDelta;\n if (!delta) return;\n\n if (delta.isFinal) return;\n\n if (streamCompletedRef.current) return;\n\n if (!pendingRef.current) {\n if (!reconnectedStreamRef.current) {\n reconnectedStreamRef.current = true;\n accumulatedLenRef.current = 0;\n }\n }\n\n hasReceivedDeltasRef.current = true;\n\n const fullText = stripModelCostHeader(delta.text ?? '');\n const newChunk = fullText.substring(accumulatedLenRef.current);\n accumulatedLenRef.current = fullText.length;\n\n if (newChunk) {\n cbRef.current.onChunk(newChunk);\n }\n },\n onError: (err) => {\n console.error('[useCdecliChannel] stream delta subscription error:', err);\n },\n });\n\n useGatewayInboundMessageByChannelSubscription({\n variables: { channelId: streamChannelId },\n skip: !isConnected || streamSkip,\n onData: ({ data }) => {\n const msg = data?.data?.gatewayInboundMessageByChannel;\n if (!msg?.text) return;\n const sanitizedText = stripModelCostHeader(msg.text);\n\n if (!hasReceivedDeltasRef.current) {\n cbRef.current.onChunk(sanitizedText);\n }\n\n cbRef.current.onComplete(sanitizedText);\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = true;\n accumulatedLenRef.current = 0;\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n },\n onError: (err) => {\n console.error('[useCdecliChannel] subscription error:', err);\n cbRef.current.onError(err.message || 'CDeCLI subscription error');\n },\n });\n\n const sendMessage = useCallback(\n async (text: string, chatId = 'messenger'): Promise<boolean> => {\n if (!isConnected) return false;\n\n pendingRef.current = { text, sentAt: Date.now() };\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = false;\n accumulatedLenRef.current = 0;\n\n try {\n const result = await sendMutation({\n variables: {\n input: {\n channelType: 'cdecli-serve',\n accountId,\n chatId,\n text,\n ...(model || skill\n ? { metadata: { ...(model && { model }), ...(skill && { skill }) } }\n : {}),\n },\n },\n });\n\n const payload = result.data?.gatewaySendMessage;\n if (!payload?.success) {\n const errMsg = payload?.error || 'CDeCLI send failed';\n cbRef.current.onError(errMsg);\n pendingRef.current = null;\n return false;\n }\n\n timeoutRef.current = setTimeout(() => {\n if (pendingRef.current) {\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n timeoutRef.current = null;\n cbRef.current.onError(\n 'CDeCLI agent did not respond within 120 seconds. The query may still be processing.',\n );\n }\n }, CDECLI_RESPONSE_TIMEOUT_MS);\n\n return true;\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n cbRef.current.onError(msg);\n pendingRef.current = null;\n return false;\n }\n },\n [isConnected, accountId, channelId, sendMutation, model, skill],\n );\n\n useEffect(\n () => () => {\n pendingRef.current = null;\n hasReceivedDeltasRef.current = false;\n reconnectedStreamRef.current = false;\n streamCompletedRef.current = false;\n accumulatedLenRef.current = 0;\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n },\n [],\n );\n\n return { sendMessage };\n}\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAYA,SAAS,qBAAqB,OAAyB,EAAA;AACrD,EAAA,MAAM,UAAa,GAAA,OAAA,CAAQ,OAAQ,CAAA,OAAA,EAAS,IAAI,CAAA;AAChD,EAAO,OAAA,UAAA,CAAW,OAAQ,CAAA,uFAAA,EAAyF,EAAE,CAAA;AACvH;AAQA,MAAM,0BAA6B,GAAA,IAAA;AAC5B,SAAS,iBAAiB,WAAsB,EAAA,SAAA,EAAmB,SAA+B,EAAA,SAAA,EAAmC,OAAgB,KAAgB,EAAA;AAC1K,EAAM,MAAA,CAAC,YAAY,CAAA,GAAI,6BAA8B,EAAA;AACrD,EAAM,MAAA,KAAA,GAAQ,OAAO,SAAS,CAAA;AAC9B,EAAA,KAAA,CAAM,OAAU,GAAA,SAAA;AAChB,EAAM,MAAA,UAAA,GAAa,OAGT,IAAI,CAAA;AACd,EAAM,MAAA,oBAAA,GAAuB,OAAO,KAAK,CAAA;AACzC,EAAM,MAAA,oBAAA,GAAuB,OAAO,KAAK,CAAA;AACzC,EAAM,MAAA,kBAAA,GAAqB,OAAO,KAAK,CAAA;AACvC,EAAM,MAAA,iBAAA,GAAoB,OAAO,CAAC,CAAA;AAClC,EAAM,MAAA,UAAA,GAAa,OAA6C,IAAI,CAAA;AACpE,EAAA,MAAM,aAAa,CAAC,SAAA;AACpB,EAAA,MAAM,kBAAkB,SAAa,IAAA,SAAA;AACrC,EAAoC,mCAAA,CAAA;AAAA,IAClC,SAAW,EAAA;AAAA,MACT,SAAW,EAAA;AAAA,KACb;AAAA,IACA,IAAM,EAAA,UAAA;AAAA,IACN,QAAQ,CAAC;AAAA,MACP;AAAA,KACI,KAAA;AA9CV,MAAA,IAAA,EAAA,EAAA,EAAA;AA+CM,MAAM,MAAA,KAAA,GAAA,CAAQ,EAAM,GAAA,IAAA,IAAA,IAAA,GAAA,MAAA,GAAA,IAAA,CAAA,IAAA,KAAN,IAAY,GAAA,MAAA,GAAA,EAAA,CAAA,oBAAA;AAC1B,MAAA,IAAI,CAAC,KAAO,EAAA;AACZ,MAAA,IAAI,MAAM,OAAS,EAAA;AACnB,MAAA,IAAI,mBAAmB,OAAS,EAAA;AAChC,MAAI,IAAA,CAAC,WAAW,OAAS,EAAA;AACvB,QAAI,IAAA,CAAC,qBAAqB,OAAS,EAAA;AACjC,UAAA,oBAAA,CAAqB,OAAU,GAAA,IAAA;AAC/B,UAAA,iBAAA,CAAkB,OAAU,GAAA,CAAA;AAAA;AAC9B;AAEF,MAAA,oBAAA,CAAqB,OAAU,GAAA,IAAA;AAC/B,MAAA,MAAM,QAAW,GAAA,oBAAA,CAAA,CAAqB,EAAM,GAAA,KAAA,CAAA,IAAA,KAAN,YAAc,EAAE,CAAA;AACtD,MAAA,MAAM,QAAW,GAAA,QAAA,CAAS,SAAU,CAAA,iBAAA,CAAkB,OAAO,CAAA;AAC7D,MAAA,iBAAA,CAAkB,UAAU,QAAS,CAAA,MAAA;AACrC,MAAA,IAAI,QAAU,EAAA;AACZ,QAAM,KAAA,CAAA,OAAA,CAAQ,QAAQ,QAAQ,CAAA;AAAA;AAChC,KACF;AAAA,IACA,SAAS,CAAO,GAAA,KAAA;AACd,MAAQ,OAAA,CAAA,KAAA,CAAM,uDAAuD,GAAG,CAAA;AAAA;AAC1E,GACD,CAAA;AACD,EAA8C,6CAAA,CAAA;AAAA,IAC5C,SAAW,EAAA;AAAA,MACT,SAAW,EAAA;AAAA,KACb;AAAA,IACA,IAAA,EAAM,CAAC,WAAe,IAAA,UAAA;AAAA,IACtB,QAAQ,CAAC;AAAA,MACP;AAAA,KACI,KAAA;AA5EV,MAAA,IAAA,EAAA;AA6EM,MAAM,MAAA,GAAA,GAAA,CAAM,EAAM,GAAA,IAAA,IAAA,IAAA,GAAA,MAAA,GAAA,IAAA,CAAA,IAAA,KAAN,IAAY,GAAA,MAAA,GAAA,EAAA,CAAA,8BAAA;AACxB,MAAI,IAAA,EAAC,2BAAK,IAAM,CAAA,EAAA;AAChB,MAAM,MAAA,aAAA,GAAgB,oBAAqB,CAAA,GAAA,CAAI,IAAI,CAAA;AACnD,MAAI,IAAA,CAAC,qBAAqB,OAAS,EAAA;AACjC,QAAM,KAAA,CAAA,OAAA,CAAQ,QAAQ,aAAa,CAAA;AAAA;AAErC,MAAM,KAAA,CAAA,OAAA,CAAQ,WAAW,aAAa,CAAA;AACtC,MAAA,UAAA,CAAW,OAAU,GAAA,IAAA;AACrB,MAAA,oBAAA,CAAqB,OAAU,GAAA,KAAA;AAC/B,MAAA,oBAAA,CAAqB,OAAU,GAAA,KAAA;AAC/B,MAAA,kBAAA,CAAmB,OAAU,GAAA,IAAA;AAC7B,MAAA,iBAAA,CAAkB,OAAU,GAAA,CAAA;AAC5B,MAAA,IAAI,WAAW,OAAS,EAAA;AACtB,QAAA,YAAA,CAAa,WAAW,OAAO,CAAA;AAC/B,QAAA,UAAA,CAAW,OAAU,GAAA,IAAA;AAAA;AACvB,KACF;AAAA,IACA,SAAS,CAAO,GAAA,KAAA;AACd,MAAQ,OAAA,CAAA,KAAA,CAAM,0CAA0C,GAAG,CAAA;AAC3D,MAAA,KAAA,CAAM,OAAQ,CAAA,OAAA,CAAQ,GAAI,CAAA,OAAA,IAAW,2BAA2B,CAAA;AAAA;AAClE,GACD,CAAA;AACD,EAAA,MAAM,WAAc,GAAA,WAAA,CAAY,OAAO,IAAA,EAAc,SAAS,WAAkC,KAAA;AAnGlG,IAAA,IAAA,EAAA;AAoGI,IAAI,IAAA,CAAC,aAAoB,OAAA,KAAA;AACzB,IAAA,UAAA,CAAW,OAAU,GAAA;AAAA,MACnB,IAAA;AAAA,MACA,MAAA,EAAQ,KAAK,GAAI;AAAA,KACnB;AACA,IAAA,oBAAA,CAAqB,OAAU,GAAA,KAAA;AAC/B,IAAA,oBAAA,CAAqB,OAAU,GAAA,KAAA;AAC/B,IAAA,kBAAA,CAAmB,OAAU,GAAA,KAAA;AAC7B,IAAA,iBAAA,CAAkB,OAAU,GAAA,CAAA;AAC5B,IAAI,IAAA;AACF,MAAM,MAAA,MAAA,GAAS,MAAM,YAAa,CAAA;AAAA,QAChC,SAAW,EAAA;AAAA,UACT,KAAO,EAAA,cAAA,CAAA;AAAA,YACL,WAAa,EAAA,cAAA;AAAA,YACb,SAAA;AAAA,YACA,MAAA;AAAA,YACA;AAAA,WAAA,EACI,SAAS,KAAQ,GAAA;AAAA,YACnB,QAAA,EAAU,kCACJ,KAAS,IAAA;AAAA,cACX;AAAA,gBAEE,KAAS,IAAA;AAAA,cACX;AAAA,aACF;AAAA,cAEA,EAAC;AAAA;AAET,OACD,CAAA;AACD,MAAM,MAAA,OAAA,GAAA,CAAU,EAAO,GAAA,MAAA,CAAA,IAAA,KAAP,IAAa,GAAA,KAAA,CAAA,GAAA,EAAA,CAAA,kBAAA;AAC7B,MAAI,IAAA,EAAC,mCAAS,OAAS,CAAA,EAAA;AACrB,QAAM,MAAA,MAAA,GAAA,CAAS,mCAAS,KAAS,KAAA,oBAAA;AACjC,QAAM,KAAA,CAAA,OAAA,CAAQ,QAAQ,MAAM,CAAA;AAC5B,QAAA,UAAA,CAAW,OAAU,GAAA,IAAA;AACrB,QAAO,OAAA,KAAA;AAAA;AAET,MAAW,UAAA,CAAA,OAAA,GAAU,WAAW,MAAM;AACpC,QAAA,IAAI,WAAW,OAAS,EAAA;AACtB,UAAA,UAAA,CAAW,OAAU,GAAA,IAAA;AACrB,UAAA,oBAAA,CAAqB,OAAU,GAAA,KAAA;AAC/B,UAAA,UAAA,CAAW,OAAU,GAAA,IAAA;AACrB,UAAM,KAAA,CAAA,OAAA,CAAQ,QAAQ,qFAAqF,CAAA;AAAA;AAC7G,SACC,0BAA0B,CAAA;AAC7B,MAAO,OAAA,IAAA;AAAA,aACA,GAAK,EAAA;AACZ,MAAA,MAAM,MAAM,GAAe,YAAA,KAAA,GAAQ,GAAI,CAAA,OAAA,GAAU,OAAO,GAAG,CAAA;AAC3D,MAAM,KAAA,CAAA,OAAA,CAAQ,QAAQ,GAAG,CAAA;AACzB,MAAA,UAAA,CAAW,OAAU,GAAA,IAAA;AACrB,MAAO,OAAA,KAAA;AAAA;AACT,GACF,EAAG,CAAC,WAAa,EAAA,SAAA,EAAW,WAAW,YAAc,EAAA,KAAA,EAAO,KAAK,CAAC,CAAA;AAClE,EAAA,SAAA,CAAU,MAAM,MAAM;AACpB,IAAA,UAAA,CAAW,OAAU,GAAA,IAAA;AACrB,IAAA,oBAAA,CAAqB,OAAU,GAAA,KAAA;AAC/B,IAAA,oBAAA,CAAqB,OAAU,GAAA,KAAA;AAC/B,IAAA,kBAAA,CAAmB,OAAU,GAAA,KAAA;AAC7B,IAAA,iBAAA,CAAkB,OAAU,GAAA,CAAA;AAC5B,IAAA,IAAI,WAAW,OAAS,EAAA;AACtB,MAAA,YAAA,CAAa,WAAW,OAAO,CAAA;AAC/B,MAAA,UAAA,CAAW,OAAU,GAAA,IAAA;AAAA;AACvB,GACF,EAAG,EAAE,CAAA;AACL,EAAO,OAAA;AAAA,IACL;AAAA,GACF;AACF"}
|