@base44/superagent-native 0.0.1 → 0.0.3
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/LICENSE +21 -0
- package/README.md +12 -20
- package/lib/commonjs/AgentSettingsPanel.js +155 -62
- package/lib/commonjs/AgentSettingsPanel.js.map +1 -1
- package/lib/commonjs/AgentSphereIcon.js +14 -118
- package/lib/commonjs/AgentSphereIcon.js.map +1 -1
- package/lib/commonjs/AttachmentPickerStatusModal.js +5 -4
- package/lib/commonjs/AttachmentPickerStatusModal.js.map +1 -1
- package/lib/commonjs/ChannelsPanel.js +66 -44
- package/lib/commonjs/ChannelsPanel.js.map +1 -1
- package/lib/commonjs/ConversationChat.js +38 -13
- package/lib/commonjs/ConversationChat.js.map +1 -1
- package/lib/commonjs/ConversationComposer.js +18 -13
- package/lib/commonjs/ConversationComposer.js.map +1 -1
- package/lib/commonjs/ConversationScreen.js +4 -0
- package/lib/commonjs/ConversationScreen.js.map +1 -1
- package/lib/commonjs/EditorDrawer.js +54 -24
- package/lib/commonjs/EditorDrawer.js.map +1 -1
- package/lib/commonjs/FilesPanel.js +56 -20
- package/lib/commonjs/FilesPanel.js.map +1 -1
- package/lib/commonjs/MarkdownText.js +1 -1
- package/lib/commonjs/MarkdownText.js.map +1 -1
- package/lib/commonjs/MessageActionBar.js +10 -3
- package/lib/commonjs/MessageActionBar.js.map +1 -1
- package/lib/commonjs/RenameAgentModal.js +2 -1
- package/lib/commonjs/RenameAgentModal.js.map +1 -1
- package/lib/commonjs/ShareAgentModal.js +11 -10
- package/lib/commonjs/ShareAgentModal.js.map +1 -1
- package/lib/commonjs/ShareAgentModal.styles.js +2 -2
- package/lib/commonjs/ShareAgentModal.styles.js.map +1 -1
- package/lib/commonjs/SuperagentHomeScreen.js +44 -12
- package/lib/commonjs/SuperagentHomeScreen.js.map +1 -1
- package/lib/commonjs/ToolApprovalCard.js +73 -15
- package/lib/commonjs/ToolApprovalCard.js.map +1 -1
- package/lib/commonjs/ToolCallSummary.js +19 -10
- package/lib/commonjs/ToolCallSummary.js.map +1 -1
- package/lib/commonjs/agentSphereAssets.js +327 -0
- package/lib/commonjs/agentSphereAssets.js.map +1 -0
- package/lib/commonjs/agentSphereStyles.js +3 -3
- package/lib/commonjs/agentSphereStyles.js.map +1 -1
- package/lib/commonjs/apiClient.js +7 -0
- package/lib/commonjs/apiClient.js.map +1 -1
- package/lib/commonjs/attachmentUpload.js +2 -1
- package/lib/commonjs/attachmentUpload.js.map +1 -1
- package/lib/commonjs/composerStyles.js +2 -2
- package/lib/commonjs/composerStyles.js.map +1 -1
- package/lib/commonjs/connectorBrandIcons.generated.js +625 -0
- package/lib/commonjs/connectorBrandIcons.generated.js.map +1 -0
- package/lib/commonjs/connectorBrandIcons.js +3 -55
- package/lib/commonjs/connectorBrandIcons.js.map +1 -1
- package/lib/commonjs/connectorCatalog.js +19 -1
- package/lib/commonjs/connectorCatalog.js.map +1 -1
- package/lib/commonjs/conversationParts.js +5 -4
- package/lib/commonjs/conversationParts.js.map +1 -1
- package/lib/commonjs/conversationRuntime.js +152 -9
- package/lib/commonjs/conversationRuntime.js.map +1 -1
- package/lib/commonjs/conversationStyles.js +2 -1
- package/lib/commonjs/conversationStyles.js.map +1 -1
- package/lib/commonjs/editorShellStyles.js +6 -2
- package/lib/commonjs/editorShellStyles.js.map +1 -1
- package/lib/commonjs/fileTreeUtils.js +7 -0
- package/lib/commonjs/fileTreeUtils.js.map +1 -1
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/markdownStyles.js +2 -2
- package/lib/commonjs/markdownStyles.js.map +1 -1
- package/lib/commonjs/messageActionStyles.js +2 -2
- package/lib/commonjs/messageActionStyles.js.map +1 -1
- package/lib/commonjs/realtimeClient.js +4 -1
- package/lib/commonjs/realtimeClient.js.map +1 -1
- package/lib/commonjs/renameAgentModalStyles.js +2 -2
- package/lib/commonjs/renameAgentModalStyles.js.map +1 -1
- package/lib/commonjs/screenParts.js +24 -41
- package/lib/commonjs/screenParts.js.map +1 -1
- package/lib/commonjs/styles.js +32 -21
- package/lib/commonjs/styles.js.map +1 -1
- package/lib/commonjs/superagentApiClient.js +63 -18
- package/lib/commonjs/superagentApiClient.js.map +1 -1
- package/lib/commonjs/theme.js +249 -0
- package/lib/commonjs/theme.js.map +1 -0
- package/lib/commonjs/useSuperagentConversation.js +240 -44
- package/lib/commonjs/useSuperagentConversation.js.map +1 -1
- package/lib/commonjs/useSuperagentRuntime.js +245 -105
- package/lib/commonjs/useSuperagentRuntime.js.map +1 -1
- package/lib/module/AgentSettingsPanel.js +157 -64
- package/lib/module/AgentSettingsPanel.js.map +1 -1
- package/lib/module/AgentSphereIcon.js +15 -118
- package/lib/module/AgentSphereIcon.js.map +1 -1
- package/lib/module/AttachmentPickerStatusModal.js +6 -5
- package/lib/module/AttachmentPickerStatusModal.js.map +1 -1
- package/lib/module/ChannelsPanel.js +67 -45
- package/lib/module/ChannelsPanel.js.map +1 -1
- package/lib/module/ConversationChat.js +38 -13
- package/lib/module/ConversationChat.js.map +1 -1
- package/lib/module/ConversationComposer.js +18 -13
- package/lib/module/ConversationComposer.js.map +1 -1
- package/lib/module/ConversationScreen.js +4 -0
- package/lib/module/ConversationScreen.js.map +1 -1
- package/lib/module/EditorDrawer.js +55 -25
- package/lib/module/EditorDrawer.js.map +1 -1
- package/lib/module/FilesPanel.js +56 -20
- package/lib/module/FilesPanel.js.map +1 -1
- package/lib/module/MarkdownText.js +1 -1
- package/lib/module/MarkdownText.js.map +1 -1
- package/lib/module/MessageActionBar.js +10 -3
- package/lib/module/MessageActionBar.js.map +1 -1
- package/lib/module/RenameAgentModal.js +2 -1
- package/lib/module/RenameAgentModal.js.map +1 -1
- package/lib/module/ShareAgentModal.js +11 -10
- package/lib/module/ShareAgentModal.js.map +1 -1
- package/lib/module/ShareAgentModal.styles.js +2 -2
- package/lib/module/ShareAgentModal.styles.js.map +1 -1
- package/lib/module/SuperagentHomeScreen.js +45 -13
- package/lib/module/SuperagentHomeScreen.js.map +1 -1
- package/lib/module/ToolApprovalCard.js +73 -15
- package/lib/module/ToolApprovalCard.js.map +1 -1
- package/lib/module/ToolCallSummary.js +19 -10
- package/lib/module/ToolCallSummary.js.map +1 -1
- package/lib/module/agentSphereAssets.js +323 -0
- package/lib/module/agentSphereAssets.js.map +1 -0
- package/lib/module/agentSphereStyles.js +3 -3
- package/lib/module/agentSphereStyles.js.map +1 -1
- package/lib/module/apiClient.js +7 -0
- package/lib/module/apiClient.js.map +1 -1
- package/lib/module/attachmentUpload.js +2 -1
- package/lib/module/attachmentUpload.js.map +1 -1
- package/lib/module/composerStyles.js +2 -2
- package/lib/module/composerStyles.js.map +1 -1
- package/lib/module/connectorBrandIcons.generated.js +621 -0
- package/lib/module/connectorBrandIcons.generated.js.map +1 -0
- package/lib/module/connectorBrandIcons.js +1 -53
- package/lib/module/connectorBrandIcons.js.map +1 -1
- package/lib/module/connectorCatalog.js +17 -0
- package/lib/module/connectorCatalog.js.map +1 -1
- package/lib/module/conversationParts.js +5 -4
- package/lib/module/conversationParts.js.map +1 -1
- package/lib/module/conversationRuntime.js +149 -9
- package/lib/module/conversationRuntime.js.map +1 -1
- package/lib/module/conversationStyles.js +3 -2
- package/lib/module/conversationStyles.js.map +1 -1
- package/lib/module/editorShellStyles.js +6 -2
- package/lib/module/editorShellStyles.js.map +1 -1
- package/lib/module/fileTreeUtils.js +6 -0
- package/lib/module/fileTreeUtils.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/markdownStyles.js +2 -2
- package/lib/module/markdownStyles.js.map +1 -1
- package/lib/module/messageActionStyles.js +2 -2
- package/lib/module/messageActionStyles.js.map +1 -1
- package/lib/module/realtimeClient.js +4 -1
- package/lib/module/realtimeClient.js.map +1 -1
- package/lib/module/renameAgentModalStyles.js +2 -2
- package/lib/module/renameAgentModalStyles.js.map +1 -1
- package/lib/module/screenParts.js +25 -42
- package/lib/module/screenParts.js.map +1 -1
- package/lib/module/styles.js +32 -21
- package/lib/module/styles.js.map +1 -1
- package/lib/module/superagentApiClient.js +63 -18
- package/lib/module/superagentApiClient.js.map +1 -1
- package/lib/module/theme.js +239 -0
- package/lib/module/theme.js.map +1 -0
- package/lib/module/useSuperagentConversation.js +242 -46
- package/lib/module/useSuperagentConversation.js.map +1 -1
- package/lib/module/useSuperagentRuntime.js +246 -106
- package/lib/module/useSuperagentRuntime.js.map +1 -1
- package/lib/typescript/commonjs/AgentSettingsPanel.d.ts.map +1 -1
- package/lib/typescript/commonjs/AgentSphereIcon.d.ts.map +1 -1
- package/lib/typescript/commonjs/AttachmentPickerStatusModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/ChannelsPanel.d.ts.map +1 -1
- package/lib/typescript/commonjs/ConversationChat.d.ts +1 -1
- package/lib/typescript/commonjs/ConversationChat.d.ts.map +1 -1
- package/lib/typescript/commonjs/ConversationComposer.d.ts.map +1 -1
- package/lib/typescript/commonjs/ConversationMessageList.d.ts +1 -1
- package/lib/typescript/commonjs/ConversationMessageList.d.ts.map +1 -1
- package/lib/typescript/commonjs/ConversationScreen.d.ts +2 -1
- package/lib/typescript/commonjs/ConversationScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/EditorDrawer.d.ts +1 -1
- package/lib/typescript/commonjs/EditorDrawer.d.ts.map +1 -1
- package/lib/typescript/commonjs/FilesPanel.d.ts.map +1 -1
- package/lib/typescript/commonjs/RenameAgentModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/ShareAgentModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/ShareAgentModal.styles.d.ts.map +1 -1
- package/lib/typescript/commonjs/SuperagentHomeScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ToolApprovalCard.d.ts +3 -3
- package/lib/typescript/commonjs/ToolApprovalCard.d.ts.map +1 -1
- package/lib/typescript/commonjs/ToolCallSummary.d.ts +1 -1
- package/lib/typescript/commonjs/ToolCallSummary.d.ts.map +1 -1
- package/lib/typescript/commonjs/agentSphereAssets.d.ts +2 -0
- package/lib/typescript/commonjs/agentSphereAssets.d.ts.map +1 -0
- package/lib/typescript/commonjs/agentSphereStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/apiClient.d.ts.map +1 -1
- package/lib/typescript/commonjs/composerStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/connectorBrandIcons.d.ts.map +1 -1
- package/lib/typescript/commonjs/connectorBrandIcons.generated.d.ts +2 -0
- package/lib/typescript/commonjs/connectorBrandIcons.generated.d.ts.map +1 -0
- package/lib/typescript/commonjs/connectorCatalog.d.ts +2 -0
- package/lib/typescript/commonjs/connectorCatalog.d.ts.map +1 -1
- package/lib/typescript/commonjs/conversationParts.d.ts +1 -1
- package/lib/typescript/commonjs/conversationParts.d.ts.map +1 -1
- package/lib/typescript/commonjs/conversationRuntime.d.ts +9 -3
- package/lib/typescript/commonjs/conversationRuntime.d.ts.map +1 -1
- package/lib/typescript/commonjs/conversationStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/editorShellStyles.d.ts +4 -0
- package/lib/typescript/commonjs/editorShellStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/fileTreeUtils.d.ts +1 -0
- package/lib/typescript/commonjs/fileTreeUtils.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +2 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/markdownStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/messageActionStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/realtimeClient.d.ts.map +1 -1
- package/lib/typescript/commonjs/renameAgentModalStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/screenParts.d.ts +1 -1
- package/lib/typescript/commonjs/screenParts.d.ts.map +1 -1
- package/lib/typescript/commonjs/styles.d.ts +20 -11
- package/lib/typescript/commonjs/styles.d.ts.map +1 -1
- package/lib/typescript/commonjs/superagentApiClient.d.ts +2 -1
- package/lib/typescript/commonjs/superagentApiClient.d.ts.map +1 -1
- package/lib/typescript/commonjs/theme.d.ts +36 -0
- package/lib/typescript/commonjs/theme.d.ts.map +1 -0
- package/lib/typescript/commonjs/types.d.ts +17 -2
- package/lib/typescript/commonjs/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/useSuperagentConversation.d.ts +3 -2
- package/lib/typescript/commonjs/useSuperagentConversation.d.ts.map +1 -1
- package/lib/typescript/commonjs/useSuperagentRuntime.d.ts +5 -2
- package/lib/typescript/commonjs/useSuperagentRuntime.d.ts.map +1 -1
- package/lib/typescript/module/AgentSettingsPanel.d.ts.map +1 -1
- package/lib/typescript/module/AgentSphereIcon.d.ts.map +1 -1
- package/lib/typescript/module/AttachmentPickerStatusModal.d.ts.map +1 -1
- package/lib/typescript/module/ChannelsPanel.d.ts.map +1 -1
- package/lib/typescript/module/ConversationChat.d.ts +1 -1
- package/lib/typescript/module/ConversationChat.d.ts.map +1 -1
- package/lib/typescript/module/ConversationComposer.d.ts.map +1 -1
- package/lib/typescript/module/ConversationMessageList.d.ts +1 -1
- package/lib/typescript/module/ConversationMessageList.d.ts.map +1 -1
- package/lib/typescript/module/ConversationScreen.d.ts +2 -1
- package/lib/typescript/module/ConversationScreen.d.ts.map +1 -1
- package/lib/typescript/module/EditorDrawer.d.ts +1 -1
- package/lib/typescript/module/EditorDrawer.d.ts.map +1 -1
- package/lib/typescript/module/FilesPanel.d.ts.map +1 -1
- package/lib/typescript/module/RenameAgentModal.d.ts.map +1 -1
- package/lib/typescript/module/ShareAgentModal.d.ts.map +1 -1
- package/lib/typescript/module/ShareAgentModal.styles.d.ts.map +1 -1
- package/lib/typescript/module/SuperagentHomeScreen.d.ts.map +1 -1
- package/lib/typescript/module/ToolApprovalCard.d.ts +3 -3
- package/lib/typescript/module/ToolApprovalCard.d.ts.map +1 -1
- package/lib/typescript/module/ToolCallSummary.d.ts +1 -1
- package/lib/typescript/module/ToolCallSummary.d.ts.map +1 -1
- package/lib/typescript/module/agentSphereAssets.d.ts +2 -0
- package/lib/typescript/module/agentSphereAssets.d.ts.map +1 -0
- package/lib/typescript/module/agentSphereStyles.d.ts.map +1 -1
- package/lib/typescript/module/apiClient.d.ts.map +1 -1
- package/lib/typescript/module/composerStyles.d.ts.map +1 -1
- package/lib/typescript/module/connectorBrandIcons.d.ts.map +1 -1
- package/lib/typescript/module/connectorBrandIcons.generated.d.ts +2 -0
- package/lib/typescript/module/connectorBrandIcons.generated.d.ts.map +1 -0
- package/lib/typescript/module/connectorCatalog.d.ts +2 -0
- package/lib/typescript/module/connectorCatalog.d.ts.map +1 -1
- package/lib/typescript/module/conversationParts.d.ts +1 -1
- package/lib/typescript/module/conversationParts.d.ts.map +1 -1
- package/lib/typescript/module/conversationRuntime.d.ts +9 -3
- package/lib/typescript/module/conversationRuntime.d.ts.map +1 -1
- package/lib/typescript/module/conversationStyles.d.ts.map +1 -1
- package/lib/typescript/module/editorShellStyles.d.ts +4 -0
- package/lib/typescript/module/editorShellStyles.d.ts.map +1 -1
- package/lib/typescript/module/fileTreeUtils.d.ts +1 -0
- package/lib/typescript/module/fileTreeUtils.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +2 -0
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/markdownStyles.d.ts.map +1 -1
- package/lib/typescript/module/messageActionStyles.d.ts.map +1 -1
- package/lib/typescript/module/realtimeClient.d.ts.map +1 -1
- package/lib/typescript/module/renameAgentModalStyles.d.ts.map +1 -1
- package/lib/typescript/module/screenParts.d.ts +1 -1
- package/lib/typescript/module/screenParts.d.ts.map +1 -1
- package/lib/typescript/module/styles.d.ts +20 -11
- package/lib/typescript/module/styles.d.ts.map +1 -1
- package/lib/typescript/module/superagentApiClient.d.ts +2 -1
- package/lib/typescript/module/superagentApiClient.d.ts.map +1 -1
- package/lib/typescript/module/theme.d.ts +36 -0
- package/lib/typescript/module/theme.d.ts.map +1 -0
- package/lib/typescript/module/types.d.ts +17 -2
- package/lib/typescript/module/types.d.ts.map +1 -1
- package/lib/typescript/module/useSuperagentConversation.d.ts +3 -2
- package/lib/typescript/module/useSuperagentConversation.d.ts.map +1 -1
- package/lib/typescript/module/useSuperagentRuntime.d.ts +5 -2
- package/lib/typescript/module/useSuperagentRuntime.d.ts.map +1 -1
- package/package.json +13 -11
- package/src/AgentSettingsPanel.tsx +146 -58
- package/src/AgentSphereIcon.tsx +11 -62
- package/src/AttachmentPickerStatusModal.tsx +6 -5
- package/src/ChannelsPanel.tsx +59 -39
- package/src/ConversationChat.tsx +49 -12
- package/src/ConversationComposer.tsx +18 -12
- package/src/ConversationMessageList.tsx +1 -1
- package/src/ConversationScreen.tsx +5 -0
- package/src/EditorDrawer.tsx +66 -41
- package/src/FilesPanel.tsx +48 -20
- package/src/MarkdownText.tsx +1 -1
- package/src/MessageActionBar.tsx +9 -3
- package/src/RenameAgentModal.tsx +2 -1
- package/src/ShareAgentModal.styles.ts +2 -1
- package/src/ShareAgentModal.tsx +9 -8
- package/src/SuperagentHomeScreen.tsx +45 -10
- package/src/ToolApprovalCard.tsx +83 -15
- package/src/ToolCallSummary.tsx +22 -13
- package/src/agentSphereAssets.ts +325 -0
- package/src/agentSphereStyles.ts +3 -2
- package/src/apiClient.ts +7 -0
- package/src/attachmentUpload.ts +2 -1
- package/src/composerStyles.ts +2 -1
- package/src/connectorBrandIcons.generated.ts +618 -0
- package/src/connectorBrandIcons.tsx +1 -53
- package/src/connectorCatalog.ts +24 -0
- package/src/conversationParts.tsx +6 -5
- package/src/conversationRuntime.ts +166 -11
- package/src/conversationStyles.ts +2 -1
- package/src/editorShellStyles.ts +6 -1
- package/src/fileTreeUtils.ts +13 -0
- package/src/index.ts +2 -0
- package/src/markdownStyles.ts +2 -1
- package/src/messageActionStyles.ts +2 -1
- package/src/realtimeClient.ts +7 -1
- package/src/renameAgentModalStyles.ts +2 -1
- package/src/screenParts.tsx +17 -29
- package/src/styles.ts +25 -16
- package/src/superagentApiClient.ts +68 -18
- package/src/theme.ts +254 -0
- package/src/types.ts +22 -2
- package/src/useSuperagentConversation.ts +247 -45
- package/src/useSuperagentRuntime.ts +244 -107
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
4
|
+
import { Alert } from 'react-native';
|
|
4
5
|
import { createSuperagentNativeClient } from "./apiClient.js";
|
|
5
|
-
import { DEFAULT_SANDBOX_FILE_PATHS, normalizeFilePaths } from "./fileTreeUtils.js";
|
|
6
|
+
import { DEFAULT_SANDBOX_FILE_PATHS, normalizeFilePaths, sanitizeSandboxFilePath } from "./fileTreeUtils.js";
|
|
6
7
|
import { createSuperagentSocketClient } from "./realtimeClient.js";
|
|
7
8
|
import { createSuperagentApiClient } from "./superagentApiClient.js";
|
|
8
9
|
export function useSuperagentRuntime({
|
|
@@ -18,6 +19,10 @@ export function useSuperagentRuntime({
|
|
|
18
19
|
}), [config.baseUrl, config.currentUserId, config.getAccessToken, config.getHeaders]);
|
|
19
20
|
const [agents, setAgents] = useState([]);
|
|
20
21
|
const [activeAgentId, setActiveAgentId] = useState(initialAgentId ?? null);
|
|
22
|
+
// Always-latest active agent id, so a slow load for a previous agent can detect
|
|
23
|
+
// that the user has since switched and skip applying its (now stale) result.
|
|
24
|
+
const activeAgentIdRef = useRef(activeAgentId);
|
|
25
|
+
activeAgentIdRef.current = activeAgentId;
|
|
21
26
|
const [currentRoute, setCurrentRoute] = useState(initialAgentId ? {
|
|
22
27
|
name: 'agent',
|
|
23
28
|
agentId: initialAgentId
|
|
@@ -44,6 +49,11 @@ export function useSuperagentRuntime({
|
|
|
44
49
|
const [isLoading, setIsLoading] = useState(true);
|
|
45
50
|
const [loadError, setLoadError] = useState(null);
|
|
46
51
|
const [runtimeAuthToken, setRuntimeAuthToken] = useState(null);
|
|
52
|
+
// Caches the resolved runtime token keyed by the agent it belongs to. The
|
|
53
|
+
// runtimeAuthToken state lags an agent switch (it's cleared in a later effect),
|
|
54
|
+
// so resolveRuntimeToken must not trust it as a cache — this ref can never hand
|
|
55
|
+
// back a different agent's token.
|
|
56
|
+
const runtimeTokenRef = useRef(null);
|
|
47
57
|
const [realtimeClient, setRealtimeClient] = useState();
|
|
48
58
|
const [secrets, setSecrets] = useState([]);
|
|
49
59
|
const connectorFlowRef = useRef(null);
|
|
@@ -78,31 +88,37 @@ export function useSuperagentRuntime({
|
|
|
78
88
|
setIsLoadingConnectors(true);
|
|
79
89
|
try {
|
|
80
90
|
const connectors = await superagentService.listConnectors(agentId);
|
|
91
|
+
if (activeAgentIdRef.current !== agentId) return;
|
|
81
92
|
setAvailableConnectors(connectors.availableConnectors);
|
|
82
93
|
setConnectedConnectors(connectors.connectedConnectors);
|
|
83
94
|
} catch {
|
|
95
|
+
if (activeAgentIdRef.current !== agentId) return;
|
|
84
96
|
setAvailableConnectors([]);
|
|
85
97
|
setConnectedConnectors([]);
|
|
86
98
|
} finally {
|
|
87
|
-
setIsLoadingConnectors(false);
|
|
99
|
+
if (activeAgentIdRef.current === agentId) setIsLoadingConnectors(false);
|
|
88
100
|
}
|
|
89
101
|
}, [superagentService]);
|
|
90
102
|
const loadAutomations = useCallback(async agentId => {
|
|
91
103
|
setIsLoadingAutomations(true);
|
|
92
104
|
try {
|
|
93
105
|
const loadedAutomations = await superagentService.listAutomations(agentId);
|
|
106
|
+
if (activeAgentIdRef.current !== agentId) return;
|
|
94
107
|
setAutomations(loadedAutomations);
|
|
95
108
|
} catch {
|
|
109
|
+
if (activeAgentIdRef.current !== agentId) return;
|
|
96
110
|
setAutomations([]);
|
|
97
111
|
} finally {
|
|
98
|
-
setIsLoadingAutomations(false);
|
|
112
|
+
if (activeAgentIdRef.current === agentId) setIsLoadingAutomations(false);
|
|
99
113
|
}
|
|
100
114
|
}, [superagentService]);
|
|
101
115
|
const loadAutomationCredits = useCallback(async agentId => {
|
|
102
116
|
try {
|
|
103
117
|
const loadedCredits = await superagentService.listAutomationCredits(agentId);
|
|
118
|
+
if (activeAgentIdRef.current !== agentId) return;
|
|
104
119
|
setAutomationCredits(loadedCredits);
|
|
105
120
|
} catch {
|
|
121
|
+
if (activeAgentIdRef.current !== agentId) return;
|
|
106
122
|
setAutomationCredits({});
|
|
107
123
|
}
|
|
108
124
|
}, [superagentService]);
|
|
@@ -110,55 +126,74 @@ export function useSuperagentRuntime({
|
|
|
110
126
|
setIsLoadingFiles(true);
|
|
111
127
|
try {
|
|
112
128
|
const loadedFilePaths = await superagentService.listSandboxFiles(agentId);
|
|
129
|
+
if (activeAgentIdRef.current !== agentId) return;
|
|
113
130
|
const normalizedFilePaths = normalizeFilePaths(loadedFilePaths);
|
|
114
131
|
setFilePaths(normalizedFilePaths.length > 0 ? normalizedFilePaths : DEFAULT_SANDBOX_FILE_PATHS);
|
|
115
132
|
setFileLoadError(null);
|
|
116
133
|
setFileLoadFailed(false);
|
|
117
134
|
} catch (error) {
|
|
135
|
+
if (activeAgentIdRef.current !== agentId) return;
|
|
118
136
|
setFilePaths(DEFAULT_SANDBOX_FILE_PATHS);
|
|
119
137
|
setFileLoadError(getErrorMessage(error));
|
|
120
138
|
setFileLoadFailed(true);
|
|
121
139
|
} finally {
|
|
122
|
-
setIsLoadingFiles(false);
|
|
140
|
+
if (activeAgentIdRef.current === agentId) setIsLoadingFiles(false);
|
|
123
141
|
}
|
|
124
142
|
}, [superagentService]);
|
|
125
143
|
const loadAgentSettings = useCallback(async agentId => {
|
|
126
144
|
setIsLoadingAgentSettings(true);
|
|
127
145
|
try {
|
|
128
146
|
const loadedSecrets = await superagentService.listSecrets(agentId);
|
|
147
|
+
if (activeAgentIdRef.current !== agentId) return;
|
|
129
148
|
setSecrets(loadedSecrets);
|
|
130
149
|
} catch {
|
|
150
|
+
if (activeAgentIdRef.current !== agentId) return;
|
|
131
151
|
setSecrets([]);
|
|
132
152
|
} finally {
|
|
133
|
-
setIsLoadingAgentSettings(false);
|
|
153
|
+
if (activeAgentIdRef.current === agentId) setIsLoadingAgentSettings(false);
|
|
134
154
|
}
|
|
135
155
|
}, [superagentService]);
|
|
136
156
|
const loadCollaborators = useCallback(async agentId => {
|
|
137
157
|
setIsLoadingCollaborators(true);
|
|
138
158
|
try {
|
|
139
159
|
const loadedCollaborators = await superagentService.listCollaborators(agentId);
|
|
160
|
+
if (activeAgentIdRef.current !== agentId) return;
|
|
140
161
|
setCollaborators(loadedCollaborators);
|
|
141
162
|
} catch {
|
|
163
|
+
if (activeAgentIdRef.current !== agentId) return;
|
|
142
164
|
setCollaborators([]);
|
|
143
165
|
} finally {
|
|
144
|
-
setIsLoadingCollaborators(false);
|
|
166
|
+
if (activeAgentIdRef.current === agentId) setIsLoadingCollaborators(false);
|
|
145
167
|
}
|
|
146
168
|
}, [superagentService]);
|
|
147
169
|
const resolveRuntimeToken = useCallback(async agentId => {
|
|
148
|
-
|
|
149
|
-
|
|
170
|
+
// Use the agent-keyed ref, not the runtimeAuthToken state: the state still
|
|
171
|
+
// holds the previous agent's token during a switch (it's cleared in a later
|
|
172
|
+
// effect), so trusting it could return the wrong agent's token here.
|
|
173
|
+
const cached = runtimeTokenRef.current;
|
|
174
|
+
if (cached && cached.agentId === agentId) {
|
|
175
|
+
return cached.token;
|
|
150
176
|
}
|
|
151
177
|
const token = await superagentService.getRuntimeAuthToken(agentId);
|
|
152
|
-
|
|
178
|
+
runtimeTokenRef.current = {
|
|
179
|
+
agentId,
|
|
180
|
+
token
|
|
181
|
+
};
|
|
182
|
+
// Compare against the latest active agent (ref), not the closure-captured
|
|
183
|
+
// activeAgentId: the user may have switched agents while the fetch was in
|
|
184
|
+
// flight, and writing a stale agent's token into shared state would point
|
|
185
|
+
// realtime/channel calls at the wrong agent.
|
|
186
|
+
if (agentId === activeAgentIdRef.current) {
|
|
153
187
|
setRuntimeAuthToken(token);
|
|
154
188
|
}
|
|
155
189
|
return token;
|
|
156
|
-
}, [
|
|
190
|
+
}, [superagentService]);
|
|
157
191
|
const loadChannels = useCallback(async agentId => {
|
|
158
192
|
setIsLoadingChannels(true);
|
|
159
193
|
try {
|
|
160
194
|
const token = await resolveRuntimeToken(agentId);
|
|
161
195
|
const status = await superagentService.getChannelStatus(agentId, token);
|
|
196
|
+
if (activeAgentIdRef.current !== agentId) return;
|
|
162
197
|
setChannelStatus(current => ({
|
|
163
198
|
...status,
|
|
164
199
|
imessage: {
|
|
@@ -171,25 +206,33 @@ export function useSuperagentRuntime({
|
|
|
171
206
|
}
|
|
172
207
|
}));
|
|
173
208
|
} catch {
|
|
209
|
+
if (activeAgentIdRef.current !== agentId) return;
|
|
174
210
|
setChannelStatus({});
|
|
175
211
|
} finally {
|
|
176
|
-
setIsLoadingChannels(false);
|
|
212
|
+
if (activeAgentIdRef.current === agentId) setIsLoadingChannels(false);
|
|
177
213
|
}
|
|
178
214
|
}, [resolveRuntimeToken, superagentService]);
|
|
179
215
|
const refreshAutomations = useCallback(async agentId => {
|
|
180
216
|
await Promise.all([loadAutomations(agentId), loadAutomationCredits(agentId)]);
|
|
181
217
|
}, [loadAutomationCredits, loadAutomations]);
|
|
182
218
|
useEffect(() => {
|
|
219
|
+
// Reset per-agent state on every active-agent change (not just when it goes
|
|
220
|
+
// null) so the drawer never shows the previous agent's secrets/connectors/
|
|
221
|
+
// files/collaborators/automations during the new agent's load window — which
|
|
222
|
+
// could otherwise let a destructive action target the wrong agent.
|
|
223
|
+
setAvailableConnectors([]);
|
|
224
|
+
setAutomationCredits({});
|
|
225
|
+
setAutomations([]);
|
|
226
|
+
setChannelStatus({});
|
|
227
|
+
setCollaborators([]);
|
|
228
|
+
setConnectingChannelId(null);
|
|
229
|
+
setConnectingConnectorId(null);
|
|
230
|
+
setConnectedConnectors([]);
|
|
231
|
+
setFilePaths([]);
|
|
232
|
+
setFileLoadError(null);
|
|
233
|
+
setFileLoadFailed(false);
|
|
234
|
+
setSecrets([]);
|
|
183
235
|
if (!activeAgentId) {
|
|
184
|
-
setAvailableConnectors([]);
|
|
185
|
-
setAutomationCredits({});
|
|
186
|
-
setAutomations([]);
|
|
187
|
-
setChannelStatus({});
|
|
188
|
-
setCollaborators([]);
|
|
189
|
-
setConnectingChannelId(null);
|
|
190
|
-
setConnectedConnectors([]);
|
|
191
|
-
setFilePaths([]);
|
|
192
|
-
setSecrets([]);
|
|
193
236
|
return;
|
|
194
237
|
}
|
|
195
238
|
loadAgentSettings(activeAgentId);
|
|
@@ -227,23 +270,17 @@ export function useSuperagentRuntime({
|
|
|
227
270
|
if (!flow || flow.cancelled) {
|
|
228
271
|
return;
|
|
229
272
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if (event.status === 'error') {
|
|
238
|
-
flow.cancelled = true;
|
|
239
|
-
connectorFlowRef.current = null;
|
|
240
|
-
setConnectingConnectorId(null);
|
|
273
|
+
|
|
274
|
+
// The callback event carries no connection/connector identifier, so it can't
|
|
275
|
+
// be reliably attributed to this flow — a late callback from a superseded
|
|
276
|
+
// connect could otherwise mark the wrong flow. Don't mutate flow state here;
|
|
277
|
+
// waitForConnectorAuthorization polls the authoritative per-connection status
|
|
278
|
+
// (it detects ACTIVE/FAILED on its own). Just refresh the connector list so
|
|
279
|
+
// the UI reflects the latest state.
|
|
280
|
+
if (event.status === 'success' || event.status === 'error') {
|
|
241
281
|
await loadConnectors(flow.agentId);
|
|
242
|
-
showAlert(nativeAdapters, 'Connector failed', 'OAuth authorization did not complete. Please try connecting again.');
|
|
243
|
-
return;
|
|
244
282
|
}
|
|
245
|
-
|
|
246
|
-
}, [loadConnectors, nativeAdapters]);
|
|
283
|
+
}, [loadConnectors]);
|
|
247
284
|
useEffect(() => {
|
|
248
285
|
return nativeAdapters.subscribeToExternalAuthCallbacks?.(completePendingConnectorFromCallback);
|
|
249
286
|
}, [completePendingConnectorFromCallback, nativeAdapters]);
|
|
@@ -370,6 +407,9 @@ export function useSuperagentRuntime({
|
|
|
370
407
|
} : agent));
|
|
371
408
|
} catch (error) {
|
|
372
409
|
showAlert(nativeAdapters, 'Permissions update failed', getErrorMessage(error));
|
|
410
|
+
// Rethrow so optimistic callers (the permission toggle) can revert; the
|
|
411
|
+
// guard-config caller wraps this in try/catch since the alert already fired.
|
|
412
|
+
throw error;
|
|
373
413
|
}
|
|
374
414
|
}, [nativeAdapters, superagentService]);
|
|
375
415
|
const onSaveSecret = useCallback(async ({
|
|
@@ -382,6 +422,9 @@ export function useSuperagentRuntime({
|
|
|
382
422
|
await loadAgentSettings(agentId);
|
|
383
423
|
} catch (error) {
|
|
384
424
|
showAlert(nativeAdapters, 'Secret save failed', getErrorMessage(error));
|
|
425
|
+
// Rethrow so the form keeps the user's input instead of clearing on a
|
|
426
|
+
// failed save.
|
|
427
|
+
throw error;
|
|
385
428
|
}
|
|
386
429
|
}, [loadAgentSettings, nativeAdapters, superagentService]);
|
|
387
430
|
const onDeleteSecret = useCallback(async ({
|
|
@@ -444,7 +487,10 @@ export function useSuperagentRuntime({
|
|
|
444
487
|
const onCloneAgent = useCallback(({
|
|
445
488
|
agentId
|
|
446
489
|
}) => {
|
|
447
|
-
|
|
490
|
+
// Use the Superagent clone route — /remix-app is an app route that the web
|
|
491
|
+
// builder redirects back to /superagent/:id for user_agent apps (reopening the
|
|
492
|
+
// original instead of cloning). /clone-superagent/:id is the agent clone flow.
|
|
493
|
+
nativeAdapters.openWebUrl?.(buildWebUrl(config.webUrl ?? config.baseUrl, `/clone-superagent/${encodeURIComponent(agentId)}`));
|
|
448
494
|
}, [config.baseUrl, config.webUrl, nativeAdapters]);
|
|
449
495
|
const onDeleteAgent = useCallback(async ({
|
|
450
496
|
agentId
|
|
@@ -567,7 +613,7 @@ export function useSuperagentRuntime({
|
|
|
567
613
|
agentId,
|
|
568
614
|
path
|
|
569
615
|
}) => {
|
|
570
|
-
return superagentService.readSandboxFile(agentId, path);
|
|
616
|
+
return superagentService.readSandboxFile(agentId, sanitizeSandboxFilePath(path));
|
|
571
617
|
}, [superagentService]);
|
|
572
618
|
const onSaveSandboxFile = useCallback(async ({
|
|
573
619
|
agentId,
|
|
@@ -575,7 +621,7 @@ export function useSuperagentRuntime({
|
|
|
575
621
|
path
|
|
576
622
|
}) => {
|
|
577
623
|
try {
|
|
578
|
-
await superagentService.writeSandboxFile(agentId, path, content);
|
|
624
|
+
await superagentService.writeSandboxFile(agentId, sanitizeSandboxFilePath(path), content);
|
|
579
625
|
await loadFiles(agentId);
|
|
580
626
|
} catch (error) {
|
|
581
627
|
showAlert(nativeAdapters, 'Save failed', getErrorMessage(error));
|
|
@@ -590,12 +636,18 @@ export function useSuperagentRuntime({
|
|
|
590
636
|
if (!files?.length) {
|
|
591
637
|
return [];
|
|
592
638
|
}
|
|
639
|
+
const writtenPaths = [];
|
|
593
640
|
for (const file of files) {
|
|
594
|
-
|
|
641
|
+
const safeName = sanitizeSandboxFilePath(file.name) || 'upload';
|
|
642
|
+
// Stage uploads under a dedicated folder so a picked file named like a
|
|
643
|
+
// generated-app file (package.json, README.md, ...) can't overwrite it.
|
|
644
|
+
const safePath = `incoming_files/${safeName}`;
|
|
645
|
+
await superagentService.writeSandboxFile(agentId, safePath, file.content);
|
|
646
|
+
writtenPaths.push(safePath);
|
|
595
647
|
}
|
|
596
648
|
await loadFiles(agentId);
|
|
597
|
-
return
|
|
598
|
-
path
|
|
649
|
+
return writtenPaths.map(path => ({
|
|
650
|
+
path
|
|
599
651
|
}));
|
|
600
652
|
} catch (error) {
|
|
601
653
|
if (nativeAdapters.isAttachmentPickerCancel?.(error)) {
|
|
@@ -625,19 +677,31 @@ export function useSuperagentRuntime({
|
|
|
625
677
|
setConnectingChannelId('whatsapp');
|
|
626
678
|
try {
|
|
627
679
|
const token = await resolveRuntimeToken(agentId);
|
|
680
|
+
// Editor gate: the connect redirect only authenticates the app-user token and
|
|
681
|
+
// does not re-check live editor access, so a downgraded viewer could otherwise
|
|
682
|
+
// open it. /whatsapp/status enforces the two-layer editor check and throws
|
|
683
|
+
// (403) for viewers — require it to pass before opening the setup page.
|
|
684
|
+
await superagentService.getWhatsAppStatus(agentId, token);
|
|
628
685
|
const connectUrl = superagentService.getWhatsAppConnectUrl(agentId, token);
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
686
|
+
if (activeAgentIdRef.current === agentId) {
|
|
687
|
+
setChannelStatus(current => ({
|
|
688
|
+
...current,
|
|
689
|
+
whatsapp: {
|
|
690
|
+
...current.whatsapp,
|
|
691
|
+
connectUrl
|
|
692
|
+
}
|
|
693
|
+
}));
|
|
694
|
+
}
|
|
695
|
+
if (!nativeAdapters.openUrl) {
|
|
696
|
+
// Without a URL opener the setup page never launches; surface an error
|
|
697
|
+
// instead of completing silently (mirrors the connector OAuth flow).
|
|
698
|
+
throw new Error('This app cannot open the WhatsApp setup page. Connect WhatsApp from the web app.');
|
|
699
|
+
}
|
|
700
|
+
await nativeAdapters.openUrl(connectUrl);
|
|
637
701
|
} catch (error) {
|
|
638
702
|
showAlert(nativeAdapters, 'WhatsApp setup failed', getErrorMessage(error));
|
|
639
703
|
} finally {
|
|
640
|
-
setConnectingChannelId(null);
|
|
704
|
+
if (activeAgentIdRef.current === agentId) setConnectingChannelId(null);
|
|
641
705
|
}
|
|
642
706
|
}, [nativeAdapters, resolveRuntimeToken, superagentService]);
|
|
643
707
|
const onSetupTelegram = useCallback(async ({
|
|
@@ -648,12 +712,14 @@ export function useSuperagentRuntime({
|
|
|
648
712
|
try {
|
|
649
713
|
const runtimeToken = await resolveRuntimeToken(agentId);
|
|
650
714
|
const telegram = await superagentService.setupTelegram(agentId, runtimeToken, token);
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
715
|
+
if (activeAgentIdRef.current === agentId) {
|
|
716
|
+
setChannelStatus(current => ({
|
|
717
|
+
...current,
|
|
718
|
+
telegram
|
|
719
|
+
}));
|
|
720
|
+
}
|
|
655
721
|
} finally {
|
|
656
|
-
setConnectingChannelId(null);
|
|
722
|
+
if (activeAgentIdRef.current === agentId) setConnectingChannelId(null);
|
|
657
723
|
}
|
|
658
724
|
}, [resolveRuntimeToken, superagentService]);
|
|
659
725
|
const onDisconnectTelegram = useCallback(async ({
|
|
@@ -672,16 +738,18 @@ export function useSuperagentRuntime({
|
|
|
672
738
|
try {
|
|
673
739
|
const token = await resolveRuntimeToken(agentId);
|
|
674
740
|
await superagentService.disconnectTelegram(agentId, token);
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
741
|
+
if (activeAgentIdRef.current === agentId) {
|
|
742
|
+
setChannelStatus(current => ({
|
|
743
|
+
...current,
|
|
744
|
+
telegram: {
|
|
745
|
+
connected: false
|
|
746
|
+
}
|
|
747
|
+
}));
|
|
748
|
+
}
|
|
681
749
|
} catch (error) {
|
|
682
750
|
showAlert(nativeAdapters, 'Telegram disconnect failed', getErrorMessage(error));
|
|
683
751
|
} finally {
|
|
684
|
-
setConnectingChannelId(null);
|
|
752
|
+
if (activeAgentIdRef.current === agentId) setConnectingChannelId(null);
|
|
685
753
|
}
|
|
686
754
|
}, [nativeAdapters, resolveRuntimeToken, superagentService]);
|
|
687
755
|
const onGenerateLineCode = useCallback(async ({
|
|
@@ -691,18 +759,20 @@ export function useSuperagentRuntime({
|
|
|
691
759
|
try {
|
|
692
760
|
const token = await resolveRuntimeToken(agentId);
|
|
693
761
|
const activation = await superagentService.generateLineCode(agentId, token);
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
762
|
+
if (activeAgentIdRef.current === agentId) {
|
|
763
|
+
setChannelStatus(current => ({
|
|
764
|
+
...current,
|
|
765
|
+
line: {
|
|
766
|
+
...current.line,
|
|
767
|
+
activation,
|
|
768
|
+
connected: false
|
|
769
|
+
}
|
|
770
|
+
}));
|
|
771
|
+
}
|
|
702
772
|
} catch (error) {
|
|
703
773
|
showAlert(nativeAdapters, 'LINE setup failed', getErrorMessage(error));
|
|
704
774
|
} finally {
|
|
705
|
-
setConnectingChannelId(null);
|
|
775
|
+
if (activeAgentIdRef.current === agentId) setConnectingChannelId(null);
|
|
706
776
|
}
|
|
707
777
|
}, [nativeAdapters, resolveRuntimeToken, superagentService]);
|
|
708
778
|
const onGenerateIMessageCode = useCallback(async ({
|
|
@@ -712,20 +782,22 @@ export function useSuperagentRuntime({
|
|
|
712
782
|
try {
|
|
713
783
|
const token = await resolveRuntimeToken(agentId);
|
|
714
784
|
const activation = await superagentService.generateIMessageCode(agentId, token);
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
785
|
+
if (activeAgentIdRef.current === agentId) {
|
|
786
|
+
setChannelStatus(current => ({
|
|
787
|
+
...current,
|
|
788
|
+
imessage: {
|
|
789
|
+
...current.imessage,
|
|
790
|
+
activation,
|
|
791
|
+
connected: current.imessage?.connected ?? false
|
|
792
|
+
}
|
|
793
|
+
}));
|
|
794
|
+
}
|
|
723
795
|
return activation;
|
|
724
796
|
} catch (error) {
|
|
725
797
|
showAlert(nativeAdapters, 'iMessage setup failed', getErrorMessage(error));
|
|
726
798
|
throw error;
|
|
727
799
|
} finally {
|
|
728
|
-
setConnectingChannelId(null);
|
|
800
|
+
if (activeAgentIdRef.current === agentId) setConnectingChannelId(null);
|
|
729
801
|
}
|
|
730
802
|
}, [nativeAdapters, resolveRuntimeToken, superagentService]);
|
|
731
803
|
const onDisconnectIMessage = useCallback(async ({
|
|
@@ -744,14 +816,16 @@ export function useSuperagentRuntime({
|
|
|
744
816
|
try {
|
|
745
817
|
const token = await resolveRuntimeToken(agentId);
|
|
746
818
|
const imessage = await superagentService.disconnectIMessage(agentId, token);
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
819
|
+
if (activeAgentIdRef.current === agentId) {
|
|
820
|
+
setChannelStatus(current => ({
|
|
821
|
+
...current,
|
|
822
|
+
imessage
|
|
823
|
+
}));
|
|
824
|
+
}
|
|
751
825
|
} catch (error) {
|
|
752
826
|
showAlert(nativeAdapters, 'iMessage disconnect failed', getErrorMessage(error));
|
|
753
827
|
} finally {
|
|
754
|
-
setConnectingChannelId(null);
|
|
828
|
+
if (activeAgentIdRef.current === agentId) setConnectingChannelId(null);
|
|
755
829
|
}
|
|
756
830
|
}, [nativeAdapters, resolveRuntimeToken, superagentService]);
|
|
757
831
|
const onOpenIMessage = useCallback(async ({
|
|
@@ -759,7 +833,10 @@ export function useSuperagentRuntime({
|
|
|
759
833
|
phoneNumber
|
|
760
834
|
}) => {
|
|
761
835
|
try {
|
|
762
|
-
|
|
836
|
+
if (!nativeAdapters.openUrl) {
|
|
837
|
+
throw new Error('This app cannot open Messages. Use the web app to share the iMessage code.');
|
|
838
|
+
}
|
|
839
|
+
await nativeAdapters.openUrl(buildIMessageUrl(phoneNumber, code));
|
|
763
840
|
} catch (error) {
|
|
764
841
|
showAlert(nativeAdapters, 'iMessage link unavailable', getErrorMessage(error));
|
|
765
842
|
}
|
|
@@ -778,7 +855,11 @@ export function useSuperagentRuntime({
|
|
|
778
855
|
addFriendUrl,
|
|
779
856
|
code
|
|
780
857
|
}) => {
|
|
781
|
-
|
|
858
|
+
if (!nativeAdapters.share) {
|
|
859
|
+
showAlert(nativeAdapters, 'Sharing unavailable', 'This app cannot share the activation code. Copy it manually instead.');
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
await nativeAdapters.share({
|
|
782
863
|
message: `LINE activation code: ${code}\n${addFriendUrl}`,
|
|
783
864
|
title: 'LINE activation code',
|
|
784
865
|
url: addFriendUrl
|
|
@@ -788,7 +869,11 @@ export function useSuperagentRuntime({
|
|
|
788
869
|
code,
|
|
789
870
|
phoneNumber
|
|
790
871
|
}) => {
|
|
791
|
-
|
|
872
|
+
if (!nativeAdapters.share) {
|
|
873
|
+
showAlert(nativeAdapters, 'Sharing unavailable', 'This app cannot share the activation code. Copy it manually instead.');
|
|
874
|
+
return;
|
|
875
|
+
}
|
|
876
|
+
await nativeAdapters.share({
|
|
792
877
|
message: `Text ${code} to ${phoneNumber} to connect this Superagent on iMessage.`,
|
|
793
878
|
title: 'iMessage activation code',
|
|
794
879
|
url: buildIMessageUrl(phoneNumber, code)
|
|
@@ -824,22 +909,35 @@ export function useSuperagentRuntime({
|
|
|
824
909
|
connectorFlowRef.current = null;
|
|
825
910
|
setConnectingConnectorId(null);
|
|
826
911
|
await loadConnectors(agentId);
|
|
827
|
-
|
|
912
|
+
// Return the connection_id (string) so the connector tool-approval can
|
|
913
|
+
// submit it; fall back to `true` when the backend omits it.
|
|
914
|
+
return connection.connection_id ?? true;
|
|
828
915
|
}
|
|
829
916
|
if (!connection.redirect_url || !connection.connection_id) {
|
|
830
917
|
throw new Error('The backend did not return an authorization URL for this connector.');
|
|
831
918
|
}
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
919
|
+
if (!nativeAdapters.openUrl) {
|
|
920
|
+
// Without a URL opener the browser never launches, so polling would just
|
|
921
|
+
// time out after ~2 minutes. Fail immediately with an actionable error.
|
|
922
|
+
throw new Error('This app cannot open the authorization page. Connect this integration from the web app.');
|
|
923
|
+
}
|
|
924
|
+
await nativeAdapters.openUrl(connection.redirect_url);
|
|
925
|
+
const connected = await waitForConnectorAuthorization(superagentService, agentId, connectorId, connection.connection_id, flow);
|
|
926
|
+
|
|
927
|
+
// Only clear shared state if this flow is still the active one — a newer
|
|
928
|
+
// connect may have superseded it (and owns connectorFlowRef now).
|
|
929
|
+
if (connectorFlowRef.current === flow) {
|
|
835
930
|
connectorFlowRef.current = null;
|
|
836
931
|
setConnectingConnectorId(null);
|
|
932
|
+
}
|
|
933
|
+
if (connected) {
|
|
837
934
|
await loadConnectors(agentId);
|
|
838
|
-
return true;
|
|
839
935
|
}
|
|
840
|
-
return
|
|
936
|
+
// On success return the connection_id so the connector tool-approval can
|
|
937
|
+
// submit it for backend verification; `false` on failure.
|
|
938
|
+
return connected ? connection.connection_id : false;
|
|
841
939
|
} catch (error) {
|
|
842
|
-
if (
|
|
940
|
+
if (connectorFlowRef.current === flow) {
|
|
843
941
|
connectorFlowRef.current = null;
|
|
844
942
|
setConnectingConnectorId(null);
|
|
845
943
|
showAlert(nativeAdapters, 'Connector failed', getErrorMessage(error));
|
|
@@ -901,6 +999,7 @@ export function useSuperagentRuntime({
|
|
|
901
999
|
}
|
|
902
1000
|
}, [loadConnectors, nativeAdapters, superagentService]);
|
|
903
1001
|
return {
|
|
1002
|
+
activeAgentId,
|
|
904
1003
|
agents,
|
|
905
1004
|
apiClient,
|
|
906
1005
|
availableConnectors,
|
|
@@ -912,7 +1011,12 @@ export function useSuperagentRuntime({
|
|
|
912
1011
|
connectingConnectorId,
|
|
913
1012
|
connectedConnectors,
|
|
914
1013
|
currentRoute,
|
|
1014
|
+
// Also expose as initialRoute, the prop SuperagentHomeScreen actually consumes,
|
|
1015
|
+
// so spreading the runtime opens on the deep-linked agent (initialAgentId)
|
|
1016
|
+
// instead of defaulting to the home route.
|
|
1017
|
+
initialRoute: currentRoute,
|
|
915
1018
|
currentUserAvatarUrl: config.currentUserAvatarUrl,
|
|
1019
|
+
currentUserId: config.currentUserId,
|
|
916
1020
|
currentUserName: config.currentUserName,
|
|
917
1021
|
fileLoadError,
|
|
918
1022
|
fileLoadFailed,
|
|
@@ -965,7 +1069,10 @@ export function useSuperagentRuntime({
|
|
|
965
1069
|
onShareAgentLink,
|
|
966
1070
|
onShareIMessageCode,
|
|
967
1071
|
onShareLineCode,
|
|
968
|
-
|
|
1072
|
+
// Only expose Live Voice when the native audio adapter is actually installed;
|
|
1073
|
+
// otherwise the composer would prefer it and fail on tap ("audio callbacks are
|
|
1074
|
+
// not installed") instead of falling back to onStartVoiceInput.
|
|
1075
|
+
onStartLiveVoice: nativeAdapters.liveVoiceAudio?.startAudioCapture ? onStartLiveVoice : undefined,
|
|
969
1076
|
onSetupTelegram,
|
|
970
1077
|
onToggleAutomation,
|
|
971
1078
|
onUpdateAgentModel,
|
|
@@ -976,22 +1083,27 @@ export function useSuperagentRuntime({
|
|
|
976
1083
|
};
|
|
977
1084
|
}
|
|
978
1085
|
async function waitForConnectorAuthorization(superagentService, agentId, connectorId, connectionId, flow) {
|
|
1086
|
+
// The connection status (scoped to this flow's connectionId) is the
|
|
1087
|
+
// authoritative source of truth — not a global callback flag, which can't be
|
|
1088
|
+
// attributed to a specific flow. Returns whether the connector ended up ACTIVE.
|
|
1089
|
+
const isActive = async () => (await superagentService.getConnectorConnectionStatus(agentId, connectorId, connectionId)) === 'ACTIVE';
|
|
979
1090
|
const maxAttempts = 40;
|
|
980
1091
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
981
1092
|
if (flow.cancelled) {
|
|
982
|
-
|
|
1093
|
+
// Cancelled — but OAuth may have already completed; confirm with the
|
|
1094
|
+
// authoritative status before reporting not-connected.
|
|
1095
|
+
return isActive().catch(() => false);
|
|
983
1096
|
}
|
|
984
1097
|
await delay(3000);
|
|
985
|
-
if (flow.cancelled) {
|
|
986
|
-
return;
|
|
987
|
-
}
|
|
988
1098
|
const status = await superagentService.getConnectorConnectionStatus(agentId, connectorId, connectionId);
|
|
989
1099
|
if (status === 'ACTIVE') {
|
|
990
|
-
return;
|
|
1100
|
+
return true;
|
|
991
1101
|
}
|
|
992
1102
|
if (status === 'FAILED') {
|
|
993
1103
|
throw new Error('OAuth connection failed.');
|
|
994
1104
|
}
|
|
1105
|
+
// If the user cancelled during the delay, the next iteration's top-of-loop
|
|
1106
|
+
// check re-confirms via the authoritative status before returning.
|
|
995
1107
|
}
|
|
996
1108
|
throw new Error('Connection timed out after 2 minutes.');
|
|
997
1109
|
}
|
|
@@ -1000,20 +1112,48 @@ async function openAllowedExternalUrl(nativeAdapters, url, allowedHosts, fallbac
|
|
|
1000
1112
|
showAlert(nativeAdapters, fallbackMessage, 'The backend returned a channel link that cannot be opened safely.');
|
|
1001
1113
|
return;
|
|
1002
1114
|
}
|
|
1115
|
+
if (!nativeAdapters.openUrl) {
|
|
1116
|
+
// No URL opener: surface it instead of passing the host check and then
|
|
1117
|
+
// silently doing nothing.
|
|
1118
|
+
showAlert(nativeAdapters, fallbackMessage, 'This app cannot open external links. Use the web app instead.');
|
|
1119
|
+
return;
|
|
1120
|
+
}
|
|
1003
1121
|
try {
|
|
1004
|
-
await nativeAdapters.openUrl
|
|
1122
|
+
await nativeAdapters.openUrl(url);
|
|
1005
1123
|
} catch (error) {
|
|
1006
1124
|
showAlert(nativeAdapters, fallbackMessage, getErrorMessage(error));
|
|
1007
1125
|
}
|
|
1008
1126
|
}
|
|
1009
1127
|
function showAlert(nativeAdapters, title, message) {
|
|
1010
|
-
nativeAdapters.alert
|
|
1128
|
+
if (nativeAdapters.alert) {
|
|
1129
|
+
nativeAdapters.alert(title, message);
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
// No host alert adapter — fall back to React Native's Alert (as confirmAction
|
|
1133
|
+
// does) so connector/channel/file/model errors aren't silently swallowed.
|
|
1134
|
+
Alert.alert(title, message);
|
|
1011
1135
|
}
|
|
1012
1136
|
async function confirmAction(nativeAdapters, input) {
|
|
1013
|
-
if (
|
|
1014
|
-
return
|
|
1137
|
+
if (nativeAdapters.confirm) {
|
|
1138
|
+
return nativeAdapters.confirm(input);
|
|
1015
1139
|
}
|
|
1016
|
-
|
|
1140
|
+
|
|
1141
|
+
// No host confirm adapter — fall back to a native prompt so destructive actions
|
|
1142
|
+
// still require explicit confirmation instead of silently proceeding.
|
|
1143
|
+
return new Promise(resolve => {
|
|
1144
|
+
Alert.alert(input.title, input.message, [{
|
|
1145
|
+
onPress: () => resolve(false),
|
|
1146
|
+
style: 'cancel',
|
|
1147
|
+
text: 'Cancel'
|
|
1148
|
+
}, {
|
|
1149
|
+
onPress: () => resolve(true),
|
|
1150
|
+
style: input.destructive ? 'destructive' : 'default',
|
|
1151
|
+
text: input.confirmText ?? 'Confirm'
|
|
1152
|
+
}], {
|
|
1153
|
+
cancelable: true,
|
|
1154
|
+
onDismiss: () => resolve(false)
|
|
1155
|
+
});
|
|
1156
|
+
});
|
|
1017
1157
|
}
|
|
1018
1158
|
function buildWebUrl(baseUrl, path) {
|
|
1019
1159
|
return `${normalizeBaseUrl(baseUrl)}${path.startsWith('/') ? path : `/${path}`}`;
|