@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.
Files changed (332) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +12 -20
  3. package/lib/commonjs/AgentSettingsPanel.js +155 -62
  4. package/lib/commonjs/AgentSettingsPanel.js.map +1 -1
  5. package/lib/commonjs/AgentSphereIcon.js +14 -118
  6. package/lib/commonjs/AgentSphereIcon.js.map +1 -1
  7. package/lib/commonjs/AttachmentPickerStatusModal.js +5 -4
  8. package/lib/commonjs/AttachmentPickerStatusModal.js.map +1 -1
  9. package/lib/commonjs/ChannelsPanel.js +66 -44
  10. package/lib/commonjs/ChannelsPanel.js.map +1 -1
  11. package/lib/commonjs/ConversationChat.js +38 -13
  12. package/lib/commonjs/ConversationChat.js.map +1 -1
  13. package/lib/commonjs/ConversationComposer.js +18 -13
  14. package/lib/commonjs/ConversationComposer.js.map +1 -1
  15. package/lib/commonjs/ConversationScreen.js +4 -0
  16. package/lib/commonjs/ConversationScreen.js.map +1 -1
  17. package/lib/commonjs/EditorDrawer.js +54 -24
  18. package/lib/commonjs/EditorDrawer.js.map +1 -1
  19. package/lib/commonjs/FilesPanel.js +56 -20
  20. package/lib/commonjs/FilesPanel.js.map +1 -1
  21. package/lib/commonjs/MarkdownText.js +1 -1
  22. package/lib/commonjs/MarkdownText.js.map +1 -1
  23. package/lib/commonjs/MessageActionBar.js +10 -3
  24. package/lib/commonjs/MessageActionBar.js.map +1 -1
  25. package/lib/commonjs/RenameAgentModal.js +2 -1
  26. package/lib/commonjs/RenameAgentModal.js.map +1 -1
  27. package/lib/commonjs/ShareAgentModal.js +11 -10
  28. package/lib/commonjs/ShareAgentModal.js.map +1 -1
  29. package/lib/commonjs/ShareAgentModal.styles.js +2 -2
  30. package/lib/commonjs/ShareAgentModal.styles.js.map +1 -1
  31. package/lib/commonjs/SuperagentHomeScreen.js +44 -12
  32. package/lib/commonjs/SuperagentHomeScreen.js.map +1 -1
  33. package/lib/commonjs/ToolApprovalCard.js +73 -15
  34. package/lib/commonjs/ToolApprovalCard.js.map +1 -1
  35. package/lib/commonjs/ToolCallSummary.js +19 -10
  36. package/lib/commonjs/ToolCallSummary.js.map +1 -1
  37. package/lib/commonjs/agentSphereAssets.js +327 -0
  38. package/lib/commonjs/agentSphereAssets.js.map +1 -0
  39. package/lib/commonjs/agentSphereStyles.js +3 -3
  40. package/lib/commonjs/agentSphereStyles.js.map +1 -1
  41. package/lib/commonjs/apiClient.js +7 -0
  42. package/lib/commonjs/apiClient.js.map +1 -1
  43. package/lib/commonjs/attachmentUpload.js +2 -1
  44. package/lib/commonjs/attachmentUpload.js.map +1 -1
  45. package/lib/commonjs/composerStyles.js +2 -2
  46. package/lib/commonjs/composerStyles.js.map +1 -1
  47. package/lib/commonjs/connectorBrandIcons.generated.js +625 -0
  48. package/lib/commonjs/connectorBrandIcons.generated.js.map +1 -0
  49. package/lib/commonjs/connectorBrandIcons.js +3 -55
  50. package/lib/commonjs/connectorBrandIcons.js.map +1 -1
  51. package/lib/commonjs/connectorCatalog.js +19 -1
  52. package/lib/commonjs/connectorCatalog.js.map +1 -1
  53. package/lib/commonjs/conversationParts.js +5 -4
  54. package/lib/commonjs/conversationParts.js.map +1 -1
  55. package/lib/commonjs/conversationRuntime.js +152 -9
  56. package/lib/commonjs/conversationRuntime.js.map +1 -1
  57. package/lib/commonjs/conversationStyles.js +2 -1
  58. package/lib/commonjs/conversationStyles.js.map +1 -1
  59. package/lib/commonjs/editorShellStyles.js +6 -2
  60. package/lib/commonjs/editorShellStyles.js.map +1 -1
  61. package/lib/commonjs/fileTreeUtils.js +7 -0
  62. package/lib/commonjs/fileTreeUtils.js.map +1 -1
  63. package/lib/commonjs/index.js +7 -0
  64. package/lib/commonjs/index.js.map +1 -1
  65. package/lib/commonjs/markdownStyles.js +2 -2
  66. package/lib/commonjs/markdownStyles.js.map +1 -1
  67. package/lib/commonjs/messageActionStyles.js +2 -2
  68. package/lib/commonjs/messageActionStyles.js.map +1 -1
  69. package/lib/commonjs/realtimeClient.js +4 -1
  70. package/lib/commonjs/realtimeClient.js.map +1 -1
  71. package/lib/commonjs/renameAgentModalStyles.js +2 -2
  72. package/lib/commonjs/renameAgentModalStyles.js.map +1 -1
  73. package/lib/commonjs/screenParts.js +24 -41
  74. package/lib/commonjs/screenParts.js.map +1 -1
  75. package/lib/commonjs/styles.js +32 -21
  76. package/lib/commonjs/styles.js.map +1 -1
  77. package/lib/commonjs/superagentApiClient.js +63 -18
  78. package/lib/commonjs/superagentApiClient.js.map +1 -1
  79. package/lib/commonjs/theme.js +249 -0
  80. package/lib/commonjs/theme.js.map +1 -0
  81. package/lib/commonjs/useSuperagentConversation.js +240 -44
  82. package/lib/commonjs/useSuperagentConversation.js.map +1 -1
  83. package/lib/commonjs/useSuperagentRuntime.js +245 -105
  84. package/lib/commonjs/useSuperagentRuntime.js.map +1 -1
  85. package/lib/module/AgentSettingsPanel.js +157 -64
  86. package/lib/module/AgentSettingsPanel.js.map +1 -1
  87. package/lib/module/AgentSphereIcon.js +15 -118
  88. package/lib/module/AgentSphereIcon.js.map +1 -1
  89. package/lib/module/AttachmentPickerStatusModal.js +6 -5
  90. package/lib/module/AttachmentPickerStatusModal.js.map +1 -1
  91. package/lib/module/ChannelsPanel.js +67 -45
  92. package/lib/module/ChannelsPanel.js.map +1 -1
  93. package/lib/module/ConversationChat.js +38 -13
  94. package/lib/module/ConversationChat.js.map +1 -1
  95. package/lib/module/ConversationComposer.js +18 -13
  96. package/lib/module/ConversationComposer.js.map +1 -1
  97. package/lib/module/ConversationScreen.js +4 -0
  98. package/lib/module/ConversationScreen.js.map +1 -1
  99. package/lib/module/EditorDrawer.js +55 -25
  100. package/lib/module/EditorDrawer.js.map +1 -1
  101. package/lib/module/FilesPanel.js +56 -20
  102. package/lib/module/FilesPanel.js.map +1 -1
  103. package/lib/module/MarkdownText.js +1 -1
  104. package/lib/module/MarkdownText.js.map +1 -1
  105. package/lib/module/MessageActionBar.js +10 -3
  106. package/lib/module/MessageActionBar.js.map +1 -1
  107. package/lib/module/RenameAgentModal.js +2 -1
  108. package/lib/module/RenameAgentModal.js.map +1 -1
  109. package/lib/module/ShareAgentModal.js +11 -10
  110. package/lib/module/ShareAgentModal.js.map +1 -1
  111. package/lib/module/ShareAgentModal.styles.js +2 -2
  112. package/lib/module/ShareAgentModal.styles.js.map +1 -1
  113. package/lib/module/SuperagentHomeScreen.js +45 -13
  114. package/lib/module/SuperagentHomeScreen.js.map +1 -1
  115. package/lib/module/ToolApprovalCard.js +73 -15
  116. package/lib/module/ToolApprovalCard.js.map +1 -1
  117. package/lib/module/ToolCallSummary.js +19 -10
  118. package/lib/module/ToolCallSummary.js.map +1 -1
  119. package/lib/module/agentSphereAssets.js +323 -0
  120. package/lib/module/agentSphereAssets.js.map +1 -0
  121. package/lib/module/agentSphereStyles.js +3 -3
  122. package/lib/module/agentSphereStyles.js.map +1 -1
  123. package/lib/module/apiClient.js +7 -0
  124. package/lib/module/apiClient.js.map +1 -1
  125. package/lib/module/attachmentUpload.js +2 -1
  126. package/lib/module/attachmentUpload.js.map +1 -1
  127. package/lib/module/composerStyles.js +2 -2
  128. package/lib/module/composerStyles.js.map +1 -1
  129. package/lib/module/connectorBrandIcons.generated.js +621 -0
  130. package/lib/module/connectorBrandIcons.generated.js.map +1 -0
  131. package/lib/module/connectorBrandIcons.js +1 -53
  132. package/lib/module/connectorBrandIcons.js.map +1 -1
  133. package/lib/module/connectorCatalog.js +17 -0
  134. package/lib/module/connectorCatalog.js.map +1 -1
  135. package/lib/module/conversationParts.js +5 -4
  136. package/lib/module/conversationParts.js.map +1 -1
  137. package/lib/module/conversationRuntime.js +149 -9
  138. package/lib/module/conversationRuntime.js.map +1 -1
  139. package/lib/module/conversationStyles.js +3 -2
  140. package/lib/module/conversationStyles.js.map +1 -1
  141. package/lib/module/editorShellStyles.js +6 -2
  142. package/lib/module/editorShellStyles.js.map +1 -1
  143. package/lib/module/fileTreeUtils.js +6 -0
  144. package/lib/module/fileTreeUtils.js.map +1 -1
  145. package/lib/module/index.js +1 -0
  146. package/lib/module/index.js.map +1 -1
  147. package/lib/module/markdownStyles.js +2 -2
  148. package/lib/module/markdownStyles.js.map +1 -1
  149. package/lib/module/messageActionStyles.js +2 -2
  150. package/lib/module/messageActionStyles.js.map +1 -1
  151. package/lib/module/realtimeClient.js +4 -1
  152. package/lib/module/realtimeClient.js.map +1 -1
  153. package/lib/module/renameAgentModalStyles.js +2 -2
  154. package/lib/module/renameAgentModalStyles.js.map +1 -1
  155. package/lib/module/screenParts.js +25 -42
  156. package/lib/module/screenParts.js.map +1 -1
  157. package/lib/module/styles.js +32 -21
  158. package/lib/module/styles.js.map +1 -1
  159. package/lib/module/superagentApiClient.js +63 -18
  160. package/lib/module/superagentApiClient.js.map +1 -1
  161. package/lib/module/theme.js +239 -0
  162. package/lib/module/theme.js.map +1 -0
  163. package/lib/module/useSuperagentConversation.js +242 -46
  164. package/lib/module/useSuperagentConversation.js.map +1 -1
  165. package/lib/module/useSuperagentRuntime.js +246 -106
  166. package/lib/module/useSuperagentRuntime.js.map +1 -1
  167. package/lib/typescript/commonjs/AgentSettingsPanel.d.ts.map +1 -1
  168. package/lib/typescript/commonjs/AgentSphereIcon.d.ts.map +1 -1
  169. package/lib/typescript/commonjs/AttachmentPickerStatusModal.d.ts.map +1 -1
  170. package/lib/typescript/commonjs/ChannelsPanel.d.ts.map +1 -1
  171. package/lib/typescript/commonjs/ConversationChat.d.ts +1 -1
  172. package/lib/typescript/commonjs/ConversationChat.d.ts.map +1 -1
  173. package/lib/typescript/commonjs/ConversationComposer.d.ts.map +1 -1
  174. package/lib/typescript/commonjs/ConversationMessageList.d.ts +1 -1
  175. package/lib/typescript/commonjs/ConversationMessageList.d.ts.map +1 -1
  176. package/lib/typescript/commonjs/ConversationScreen.d.ts +2 -1
  177. package/lib/typescript/commonjs/ConversationScreen.d.ts.map +1 -1
  178. package/lib/typescript/commonjs/EditorDrawer.d.ts +1 -1
  179. package/lib/typescript/commonjs/EditorDrawer.d.ts.map +1 -1
  180. package/lib/typescript/commonjs/FilesPanel.d.ts.map +1 -1
  181. package/lib/typescript/commonjs/RenameAgentModal.d.ts.map +1 -1
  182. package/lib/typescript/commonjs/ShareAgentModal.d.ts.map +1 -1
  183. package/lib/typescript/commonjs/ShareAgentModal.styles.d.ts.map +1 -1
  184. package/lib/typescript/commonjs/SuperagentHomeScreen.d.ts.map +1 -1
  185. package/lib/typescript/commonjs/ToolApprovalCard.d.ts +3 -3
  186. package/lib/typescript/commonjs/ToolApprovalCard.d.ts.map +1 -1
  187. package/lib/typescript/commonjs/ToolCallSummary.d.ts +1 -1
  188. package/lib/typescript/commonjs/ToolCallSummary.d.ts.map +1 -1
  189. package/lib/typescript/commonjs/agentSphereAssets.d.ts +2 -0
  190. package/lib/typescript/commonjs/agentSphereAssets.d.ts.map +1 -0
  191. package/lib/typescript/commonjs/agentSphereStyles.d.ts.map +1 -1
  192. package/lib/typescript/commonjs/apiClient.d.ts.map +1 -1
  193. package/lib/typescript/commonjs/composerStyles.d.ts.map +1 -1
  194. package/lib/typescript/commonjs/connectorBrandIcons.d.ts.map +1 -1
  195. package/lib/typescript/commonjs/connectorBrandIcons.generated.d.ts +2 -0
  196. package/lib/typescript/commonjs/connectorBrandIcons.generated.d.ts.map +1 -0
  197. package/lib/typescript/commonjs/connectorCatalog.d.ts +2 -0
  198. package/lib/typescript/commonjs/connectorCatalog.d.ts.map +1 -1
  199. package/lib/typescript/commonjs/conversationParts.d.ts +1 -1
  200. package/lib/typescript/commonjs/conversationParts.d.ts.map +1 -1
  201. package/lib/typescript/commonjs/conversationRuntime.d.ts +9 -3
  202. package/lib/typescript/commonjs/conversationRuntime.d.ts.map +1 -1
  203. package/lib/typescript/commonjs/conversationStyles.d.ts.map +1 -1
  204. package/lib/typescript/commonjs/editorShellStyles.d.ts +4 -0
  205. package/lib/typescript/commonjs/editorShellStyles.d.ts.map +1 -1
  206. package/lib/typescript/commonjs/fileTreeUtils.d.ts +1 -0
  207. package/lib/typescript/commonjs/fileTreeUtils.d.ts.map +1 -1
  208. package/lib/typescript/commonjs/index.d.ts +2 -0
  209. package/lib/typescript/commonjs/index.d.ts.map +1 -1
  210. package/lib/typescript/commonjs/markdownStyles.d.ts.map +1 -1
  211. package/lib/typescript/commonjs/messageActionStyles.d.ts.map +1 -1
  212. package/lib/typescript/commonjs/realtimeClient.d.ts.map +1 -1
  213. package/lib/typescript/commonjs/renameAgentModalStyles.d.ts.map +1 -1
  214. package/lib/typescript/commonjs/screenParts.d.ts +1 -1
  215. package/lib/typescript/commonjs/screenParts.d.ts.map +1 -1
  216. package/lib/typescript/commonjs/styles.d.ts +20 -11
  217. package/lib/typescript/commonjs/styles.d.ts.map +1 -1
  218. package/lib/typescript/commonjs/superagentApiClient.d.ts +2 -1
  219. package/lib/typescript/commonjs/superagentApiClient.d.ts.map +1 -1
  220. package/lib/typescript/commonjs/theme.d.ts +36 -0
  221. package/lib/typescript/commonjs/theme.d.ts.map +1 -0
  222. package/lib/typescript/commonjs/types.d.ts +17 -2
  223. package/lib/typescript/commonjs/types.d.ts.map +1 -1
  224. package/lib/typescript/commonjs/useSuperagentConversation.d.ts +3 -2
  225. package/lib/typescript/commonjs/useSuperagentConversation.d.ts.map +1 -1
  226. package/lib/typescript/commonjs/useSuperagentRuntime.d.ts +5 -2
  227. package/lib/typescript/commonjs/useSuperagentRuntime.d.ts.map +1 -1
  228. package/lib/typescript/module/AgentSettingsPanel.d.ts.map +1 -1
  229. package/lib/typescript/module/AgentSphereIcon.d.ts.map +1 -1
  230. package/lib/typescript/module/AttachmentPickerStatusModal.d.ts.map +1 -1
  231. package/lib/typescript/module/ChannelsPanel.d.ts.map +1 -1
  232. package/lib/typescript/module/ConversationChat.d.ts +1 -1
  233. package/lib/typescript/module/ConversationChat.d.ts.map +1 -1
  234. package/lib/typescript/module/ConversationComposer.d.ts.map +1 -1
  235. package/lib/typescript/module/ConversationMessageList.d.ts +1 -1
  236. package/lib/typescript/module/ConversationMessageList.d.ts.map +1 -1
  237. package/lib/typescript/module/ConversationScreen.d.ts +2 -1
  238. package/lib/typescript/module/ConversationScreen.d.ts.map +1 -1
  239. package/lib/typescript/module/EditorDrawer.d.ts +1 -1
  240. package/lib/typescript/module/EditorDrawer.d.ts.map +1 -1
  241. package/lib/typescript/module/FilesPanel.d.ts.map +1 -1
  242. package/lib/typescript/module/RenameAgentModal.d.ts.map +1 -1
  243. package/lib/typescript/module/ShareAgentModal.d.ts.map +1 -1
  244. package/lib/typescript/module/ShareAgentModal.styles.d.ts.map +1 -1
  245. package/lib/typescript/module/SuperagentHomeScreen.d.ts.map +1 -1
  246. package/lib/typescript/module/ToolApprovalCard.d.ts +3 -3
  247. package/lib/typescript/module/ToolApprovalCard.d.ts.map +1 -1
  248. package/lib/typescript/module/ToolCallSummary.d.ts +1 -1
  249. package/lib/typescript/module/ToolCallSummary.d.ts.map +1 -1
  250. package/lib/typescript/module/agentSphereAssets.d.ts +2 -0
  251. package/lib/typescript/module/agentSphereAssets.d.ts.map +1 -0
  252. package/lib/typescript/module/agentSphereStyles.d.ts.map +1 -1
  253. package/lib/typescript/module/apiClient.d.ts.map +1 -1
  254. package/lib/typescript/module/composerStyles.d.ts.map +1 -1
  255. package/lib/typescript/module/connectorBrandIcons.d.ts.map +1 -1
  256. package/lib/typescript/module/connectorBrandIcons.generated.d.ts +2 -0
  257. package/lib/typescript/module/connectorBrandIcons.generated.d.ts.map +1 -0
  258. package/lib/typescript/module/connectorCatalog.d.ts +2 -0
  259. package/lib/typescript/module/connectorCatalog.d.ts.map +1 -1
  260. package/lib/typescript/module/conversationParts.d.ts +1 -1
  261. package/lib/typescript/module/conversationParts.d.ts.map +1 -1
  262. package/lib/typescript/module/conversationRuntime.d.ts +9 -3
  263. package/lib/typescript/module/conversationRuntime.d.ts.map +1 -1
  264. package/lib/typescript/module/conversationStyles.d.ts.map +1 -1
  265. package/lib/typescript/module/editorShellStyles.d.ts +4 -0
  266. package/lib/typescript/module/editorShellStyles.d.ts.map +1 -1
  267. package/lib/typescript/module/fileTreeUtils.d.ts +1 -0
  268. package/lib/typescript/module/fileTreeUtils.d.ts.map +1 -1
  269. package/lib/typescript/module/index.d.ts +2 -0
  270. package/lib/typescript/module/index.d.ts.map +1 -1
  271. package/lib/typescript/module/markdownStyles.d.ts.map +1 -1
  272. package/lib/typescript/module/messageActionStyles.d.ts.map +1 -1
  273. package/lib/typescript/module/realtimeClient.d.ts.map +1 -1
  274. package/lib/typescript/module/renameAgentModalStyles.d.ts.map +1 -1
  275. package/lib/typescript/module/screenParts.d.ts +1 -1
  276. package/lib/typescript/module/screenParts.d.ts.map +1 -1
  277. package/lib/typescript/module/styles.d.ts +20 -11
  278. package/lib/typescript/module/styles.d.ts.map +1 -1
  279. package/lib/typescript/module/superagentApiClient.d.ts +2 -1
  280. package/lib/typescript/module/superagentApiClient.d.ts.map +1 -1
  281. package/lib/typescript/module/theme.d.ts +36 -0
  282. package/lib/typescript/module/theme.d.ts.map +1 -0
  283. package/lib/typescript/module/types.d.ts +17 -2
  284. package/lib/typescript/module/types.d.ts.map +1 -1
  285. package/lib/typescript/module/useSuperagentConversation.d.ts +3 -2
  286. package/lib/typescript/module/useSuperagentConversation.d.ts.map +1 -1
  287. package/lib/typescript/module/useSuperagentRuntime.d.ts +5 -2
  288. package/lib/typescript/module/useSuperagentRuntime.d.ts.map +1 -1
  289. package/package.json +13 -11
  290. package/src/AgentSettingsPanel.tsx +146 -58
  291. package/src/AgentSphereIcon.tsx +11 -62
  292. package/src/AttachmentPickerStatusModal.tsx +6 -5
  293. package/src/ChannelsPanel.tsx +59 -39
  294. package/src/ConversationChat.tsx +49 -12
  295. package/src/ConversationComposer.tsx +18 -12
  296. package/src/ConversationMessageList.tsx +1 -1
  297. package/src/ConversationScreen.tsx +5 -0
  298. package/src/EditorDrawer.tsx +66 -41
  299. package/src/FilesPanel.tsx +48 -20
  300. package/src/MarkdownText.tsx +1 -1
  301. package/src/MessageActionBar.tsx +9 -3
  302. package/src/RenameAgentModal.tsx +2 -1
  303. package/src/ShareAgentModal.styles.ts +2 -1
  304. package/src/ShareAgentModal.tsx +9 -8
  305. package/src/SuperagentHomeScreen.tsx +45 -10
  306. package/src/ToolApprovalCard.tsx +83 -15
  307. package/src/ToolCallSummary.tsx +22 -13
  308. package/src/agentSphereAssets.ts +325 -0
  309. package/src/agentSphereStyles.ts +3 -2
  310. package/src/apiClient.ts +7 -0
  311. package/src/attachmentUpload.ts +2 -1
  312. package/src/composerStyles.ts +2 -1
  313. package/src/connectorBrandIcons.generated.ts +618 -0
  314. package/src/connectorBrandIcons.tsx +1 -53
  315. package/src/connectorCatalog.ts +24 -0
  316. package/src/conversationParts.tsx +6 -5
  317. package/src/conversationRuntime.ts +166 -11
  318. package/src/conversationStyles.ts +2 -1
  319. package/src/editorShellStyles.ts +6 -1
  320. package/src/fileTreeUtils.ts +13 -0
  321. package/src/index.ts +2 -0
  322. package/src/markdownStyles.ts +2 -1
  323. package/src/messageActionStyles.ts +2 -1
  324. package/src/realtimeClient.ts +7 -1
  325. package/src/renameAgentModalStyles.ts +2 -1
  326. package/src/screenParts.tsx +17 -29
  327. package/src/styles.ts +25 -16
  328. package/src/superagentApiClient.ts +68 -18
  329. package/src/theme.ts +254 -0
  330. package/src/types.ts +22 -2
  331. package/src/useSuperagentConversation.ts +247 -45
  332. package/src/useSuperagentRuntime.ts +244 -107
@@ -1,6 +1,7 @@
1
1
  import {useCallback, useEffect, useMemo, useRef, useState} from 'react';
2
+ import { Alert } from 'react-native';
2
3
  import { createSuperagentNativeClient } from './apiClient';
3
- import { DEFAULT_SANDBOX_FILE_PATHS, normalizeFilePaths } from './fileTreeUtils';
4
+ import { DEFAULT_SANDBOX_FILE_PATHS, normalizeFilePaths, sanitizeSandboxFilePath } from './fileTreeUtils';
4
5
  import {
5
6
  createSuperagentSocketClient,
6
7
  type SuperagentSocketLike,
@@ -146,6 +147,10 @@ export function useSuperagentRuntime({
146
147
  }), [config.baseUrl, config.currentUserId, config.getAccessToken, config.getHeaders]);
147
148
  const [agents, setAgents] = useState<SuperagentAgent[]>([]);
148
149
  const [activeAgentId, setActiveAgentId] = useState<string | null>(initialAgentId ?? null);
150
+ // Always-latest active agent id, so a slow load for a previous agent can detect
151
+ // that the user has since switched and skip applying its (now stale) result.
152
+ const activeAgentIdRef = useRef(activeAgentId);
153
+ activeAgentIdRef.current = activeAgentId;
149
154
  const [currentRoute, setCurrentRoute] = useState<SuperagentRoute>(
150
155
  initialAgentId ? {name: 'agent', agentId: initialAgentId} : {name: 'home'},
151
156
  );
@@ -169,6 +174,11 @@ export function useSuperagentRuntime({
169
174
  const [isLoading, setIsLoading] = useState(true);
170
175
  const [loadError, setLoadError] = useState<string | null>(null);
171
176
  const [runtimeAuthToken, setRuntimeAuthToken] = useState<string | null>(null);
177
+ // Caches the resolved runtime token keyed by the agent it belongs to. The
178
+ // runtimeAuthToken state lags an agent switch (it's cleared in a later effect),
179
+ // so resolveRuntimeToken must not trust it as a cache — this ref can never hand
180
+ // back a different agent's token.
181
+ const runtimeTokenRef = useRef<{ agentId: string; token: string } | null>(null);
172
182
  const [realtimeClient, setRealtimeClient] = useState<SuperagentRealtimeClient | undefined>();
173
183
  const [secrets, setSecrets] = useState<SuperagentSecret[]>([]);
174
184
  const connectorFlowRef = useRef<ConnectorFlow | null>(null);
@@ -209,13 +219,15 @@ export function useSuperagentRuntime({
209
219
  setIsLoadingConnectors(true);
210
220
  try {
211
221
  const connectors = await superagentService.listConnectors(agentId);
222
+ if (activeAgentIdRef.current !== agentId) return;
212
223
  setAvailableConnectors(connectors.availableConnectors);
213
224
  setConnectedConnectors(connectors.connectedConnectors);
214
225
  } catch {
226
+ if (activeAgentIdRef.current !== agentId) return;
215
227
  setAvailableConnectors([]);
216
228
  setConnectedConnectors([]);
217
229
  } finally {
218
- setIsLoadingConnectors(false);
230
+ if (activeAgentIdRef.current === agentId) setIsLoadingConnectors(false);
219
231
  }
220
232
  }, [superagentService]);
221
233
 
@@ -223,19 +235,23 @@ export function useSuperagentRuntime({
223
235
  setIsLoadingAutomations(true);
224
236
  try {
225
237
  const loadedAutomations = await superagentService.listAutomations(agentId);
238
+ if (activeAgentIdRef.current !== agentId) return;
226
239
  setAutomations(loadedAutomations);
227
240
  } catch {
241
+ if (activeAgentIdRef.current !== agentId) return;
228
242
  setAutomations([]);
229
243
  } finally {
230
- setIsLoadingAutomations(false);
244
+ if (activeAgentIdRef.current === agentId) setIsLoadingAutomations(false);
231
245
  }
232
246
  }, [superagentService]);
233
247
 
234
248
  const loadAutomationCredits = useCallback(async (agentId: string) => {
235
249
  try {
236
250
  const loadedCredits = await superagentService.listAutomationCredits(agentId);
251
+ if (activeAgentIdRef.current !== agentId) return;
237
252
  setAutomationCredits(loadedCredits);
238
253
  } catch {
254
+ if (activeAgentIdRef.current !== agentId) return;
239
255
  setAutomationCredits({});
240
256
  }
241
257
  }, [superagentService]);
@@ -244,16 +260,18 @@ export function useSuperagentRuntime({
244
260
  setIsLoadingFiles(true);
245
261
  try {
246
262
  const loadedFilePaths = await superagentService.listSandboxFiles(agentId);
263
+ if (activeAgentIdRef.current !== agentId) return;
247
264
  const normalizedFilePaths = normalizeFilePaths(loadedFilePaths);
248
265
  setFilePaths(normalizedFilePaths.length > 0 ? normalizedFilePaths : DEFAULT_SANDBOX_FILE_PATHS);
249
266
  setFileLoadError(null);
250
267
  setFileLoadFailed(false);
251
268
  } catch (error) {
269
+ if (activeAgentIdRef.current !== agentId) return;
252
270
  setFilePaths(DEFAULT_SANDBOX_FILE_PATHS);
253
271
  setFileLoadError(getErrorMessage(error));
254
272
  setFileLoadFailed(true);
255
273
  } finally {
256
- setIsLoadingFiles(false);
274
+ if (activeAgentIdRef.current === agentId) setIsLoadingFiles(false);
257
275
  }
258
276
  }, [superagentService]);
259
277
 
@@ -261,11 +279,13 @@ export function useSuperagentRuntime({
261
279
  setIsLoadingAgentSettings(true);
262
280
  try {
263
281
  const loadedSecrets = await superagentService.listSecrets(agentId);
282
+ if (activeAgentIdRef.current !== agentId) return;
264
283
  setSecrets(loadedSecrets);
265
284
  } catch {
285
+ if (activeAgentIdRef.current !== agentId) return;
266
286
  setSecrets([]);
267
287
  } finally {
268
- setIsLoadingAgentSettings(false);
288
+ if (activeAgentIdRef.current === agentId) setIsLoadingAgentSettings(false);
269
289
  }
270
290
  }, [superagentService]);
271
291
 
@@ -273,31 +293,43 @@ export function useSuperagentRuntime({
273
293
  setIsLoadingCollaborators(true);
274
294
  try {
275
295
  const loadedCollaborators = await superagentService.listCollaborators(agentId);
296
+ if (activeAgentIdRef.current !== agentId) return;
276
297
  setCollaborators(loadedCollaborators);
277
298
  } catch {
299
+ if (activeAgentIdRef.current !== agentId) return;
278
300
  setCollaborators([]);
279
301
  } finally {
280
- setIsLoadingCollaborators(false);
302
+ if (activeAgentIdRef.current === agentId) setIsLoadingCollaborators(false);
281
303
  }
282
304
  }, [superagentService]);
283
305
 
284
306
  const resolveRuntimeToken = useCallback(async (agentId: string) => {
285
- if (agentId === activeAgentId && runtimeAuthToken) {
286
- return runtimeAuthToken;
307
+ // Use the agent-keyed ref, not the runtimeAuthToken state: the state still
308
+ // holds the previous agent's token during a switch (it's cleared in a later
309
+ // effect), so trusting it could return the wrong agent's token here.
310
+ const cached = runtimeTokenRef.current;
311
+ if (cached && cached.agentId === agentId) {
312
+ return cached.token;
287
313
  }
288
314
 
289
315
  const token = await superagentService.getRuntimeAuthToken(agentId);
290
- if (agentId === activeAgentId) {
316
+ runtimeTokenRef.current = { agentId, token };
317
+ // Compare against the latest active agent (ref), not the closure-captured
318
+ // activeAgentId: the user may have switched agents while the fetch was in
319
+ // flight, and writing a stale agent's token into shared state would point
320
+ // realtime/channel calls at the wrong agent.
321
+ if (agentId === activeAgentIdRef.current) {
291
322
  setRuntimeAuthToken(token);
292
323
  }
293
324
  return token;
294
- }, [activeAgentId, runtimeAuthToken, superagentService]);
325
+ }, [superagentService]);
295
326
 
296
327
  const loadChannels = useCallback(async (agentId: string) => {
297
328
  setIsLoadingChannels(true);
298
329
  try {
299
330
  const token = await resolveRuntimeToken(agentId);
300
331
  const status = await superagentService.getChannelStatus(agentId, token);
332
+ if (activeAgentIdRef.current !== agentId) return;
301
333
  setChannelStatus((current) => ({
302
334
  ...status,
303
335
  imessage: {
@@ -310,9 +342,10 @@ export function useSuperagentRuntime({
310
342
  },
311
343
  }));
312
344
  } catch {
345
+ if (activeAgentIdRef.current !== agentId) return;
313
346
  setChannelStatus({});
314
347
  } finally {
315
- setIsLoadingChannels(false);
348
+ if (activeAgentIdRef.current === agentId) setIsLoadingChannels(false);
316
349
  }
317
350
  }, [resolveRuntimeToken, superagentService]);
318
351
 
@@ -324,16 +357,24 @@ export function useSuperagentRuntime({
324
357
  }, [loadAutomationCredits, loadAutomations]);
325
358
 
326
359
  useEffect(() => {
360
+ // Reset per-agent state on every active-agent change (not just when it goes
361
+ // null) so the drawer never shows the previous agent's secrets/connectors/
362
+ // files/collaborators/automations during the new agent's load window — which
363
+ // could otherwise let a destructive action target the wrong agent.
364
+ setAvailableConnectors([]);
365
+ setAutomationCredits({});
366
+ setAutomations([]);
367
+ setChannelStatus({});
368
+ setCollaborators([]);
369
+ setConnectingChannelId(null);
370
+ setConnectingConnectorId(null);
371
+ setConnectedConnectors([]);
372
+ setFilePaths([]);
373
+ setFileLoadError(null);
374
+ setFileLoadFailed(false);
375
+ setSecrets([]);
376
+
327
377
  if (!activeAgentId) {
328
- setAvailableConnectors([]);
329
- setAutomationCredits({});
330
- setAutomations([]);
331
- setChannelStatus({});
332
- setCollaborators([]);
333
- setConnectingChannelId(null);
334
- setConnectedConnectors([]);
335
- setFilePaths([]);
336
- setSecrets([]);
337
378
  return;
338
379
  }
339
380
 
@@ -380,25 +421,16 @@ export function useSuperagentRuntime({
380
421
  return;
381
422
  }
382
423
 
383
- if (event.status === 'success') {
384
- flow.cancelled = true;
385
- connectorFlowRef.current = null;
386
- setConnectingConnectorId(null);
424
+ // The callback event carries no connection/connector identifier, so it can't
425
+ // be reliably attributed to this flow a late callback from a superseded
426
+ // connect could otherwise mark the wrong flow. Don't mutate flow state here;
427
+ // waitForConnectorAuthorization polls the authoritative per-connection status
428
+ // (it detects ACTIVE/FAILED on its own). Just refresh the connector list so
429
+ // the UI reflects the latest state.
430
+ if (event.status === 'success' || event.status === 'error') {
387
431
  await loadConnectors(flow.agentId);
388
- return;
389
- }
390
-
391
- if (event.status === 'error') {
392
- flow.cancelled = true;
393
- connectorFlowRef.current = null;
394
- setConnectingConnectorId(null);
395
- await loadConnectors(flow.agentId);
396
- showAlert(nativeAdapters, 'Connector failed', 'OAuth authorization did not complete. Please try connecting again.');
397
- return;
398
432
  }
399
-
400
- await loadConnectors(flow.agentId);
401
- }, [loadConnectors, nativeAdapters]);
433
+ }, [loadConnectors]);
402
434
 
403
435
  useEffect(() => {
404
436
  return nativeAdapters.subscribeToExternalAuthCallbacks?.(completePendingConnectorFromCallback);
@@ -536,6 +568,9 @@ export function useSuperagentRuntime({
536
568
  )));
537
569
  } catch (error) {
538
570
  showAlert(nativeAdapters, 'Permissions update failed', getErrorMessage(error));
571
+ // Rethrow so optimistic callers (the permission toggle) can revert; the
572
+ // guard-config caller wraps this in try/catch since the alert already fired.
573
+ throw error;
539
574
  }
540
575
  }, [nativeAdapters, superagentService]);
541
576
 
@@ -545,6 +580,9 @@ export function useSuperagentRuntime({
545
580
  await loadAgentSettings(agentId);
546
581
  } catch (error) {
547
582
  showAlert(nativeAdapters, 'Secret save failed', getErrorMessage(error));
583
+ // Rethrow so the form keeps the user's input instead of clearing on a
584
+ // failed save.
585
+ throw error;
548
586
  }
549
587
  }, [loadAgentSettings, nativeAdapters, superagentService]);
550
588
 
@@ -605,7 +643,10 @@ export function useSuperagentRuntime({
605
643
  }, [config.baseUrl, config.webUrl, nativeAdapters]);
606
644
 
607
645
  const onCloneAgent = useCallback(({agentId}: SuperagentAgentActionInput) => {
608
- nativeAdapters.openWebUrl?.(buildWebUrl(config.webUrl ?? config.baseUrl, `/remix-app/${encodeURIComponent(agentId)}?clone_history=true`));
646
+ // Use the Superagent clone route — /remix-app is an app route that the web
647
+ // builder redirects back to /superagent/:id for user_agent apps (reopening the
648
+ // original instead of cloning). /clone-superagent/:id is the agent clone flow.
649
+ nativeAdapters.openWebUrl?.(buildWebUrl(config.webUrl ?? config.baseUrl, `/clone-superagent/${encodeURIComponent(agentId)}`));
609
650
  }, [config.baseUrl, config.webUrl, nativeAdapters]);
610
651
 
611
652
  const onDeleteAgent = useCallback(async ({agentId}: SuperagentAgentActionInput) => {
@@ -705,12 +746,12 @@ export function useSuperagentRuntime({
705
746
  }, [config.baseUrl, config.webUrl, nativeAdapters]);
706
747
 
707
748
  const onOpenSandboxFile = useCallback(async ({agentId, path}: SuperagentSandboxFileActionInput) => {
708
- return superagentService.readSandboxFile(agentId, path);
749
+ return superagentService.readSandboxFile(agentId, sanitizeSandboxFilePath(path));
709
750
  }, [superagentService]);
710
751
 
711
752
  const onSaveSandboxFile = useCallback(async ({agentId, content, path}: SuperagentSandboxFileSaveInput) => {
712
753
  try {
713
- await superagentService.writeSandboxFile(agentId, path, content);
754
+ await superagentService.writeSandboxFile(agentId, sanitizeSandboxFilePath(path), content);
714
755
  await loadFiles(agentId);
715
756
  } catch (error) {
716
757
  showAlert(nativeAdapters, 'Save failed', getErrorMessage(error));
@@ -725,11 +766,17 @@ export function useSuperagentRuntime({
725
766
  return [];
726
767
  }
727
768
 
769
+ const writtenPaths: string[] = [];
728
770
  for (const file of files) {
729
- await superagentService.writeSandboxFile(agentId, file.name, file.content);
771
+ const safeName = sanitizeSandboxFilePath(file.name) || 'upload';
772
+ // Stage uploads under a dedicated folder so a picked file named like a
773
+ // generated-app file (package.json, README.md, ...) can't overwrite it.
774
+ const safePath = `incoming_files/${safeName}`;
775
+ await superagentService.writeSandboxFile(agentId, safePath, file.content);
776
+ writtenPaths.push(safePath);
730
777
  }
731
778
  await loadFiles(agentId);
732
- return files.map((file) => ({path: file.name}));
779
+ return writtenPaths.map((path) => ({path}));
733
780
  } catch (error) {
734
781
  if (nativeAdapters.isAttachmentPickerCancel?.(error)) {
735
782
  return [];
@@ -760,19 +807,31 @@ export function useSuperagentRuntime({
760
807
  setConnectingChannelId('whatsapp');
761
808
  try {
762
809
  const token = await resolveRuntimeToken(agentId);
810
+ // Editor gate: the connect redirect only authenticates the app-user token and
811
+ // does not re-check live editor access, so a downgraded viewer could otherwise
812
+ // open it. /whatsapp/status enforces the two-layer editor check and throws
813
+ // (403) for viewers — require it to pass before opening the setup page.
814
+ await superagentService.getWhatsAppStatus(agentId, token);
763
815
  const connectUrl = superagentService.getWhatsAppConnectUrl(agentId, token);
764
- setChannelStatus((current) => ({
765
- ...current,
766
- whatsapp: {
767
- ...current.whatsapp,
768
- connectUrl,
769
- },
770
- }));
771
- await nativeAdapters.openUrl?.(connectUrl);
816
+ if (activeAgentIdRef.current === agentId) {
817
+ setChannelStatus((current) => ({
818
+ ...current,
819
+ whatsapp: {
820
+ ...current.whatsapp,
821
+ connectUrl,
822
+ },
823
+ }));
824
+ }
825
+ if (!nativeAdapters.openUrl) {
826
+ // Without a URL opener the setup page never launches; surface an error
827
+ // instead of completing silently (mirrors the connector OAuth flow).
828
+ throw new Error('This app cannot open the WhatsApp setup page. Connect WhatsApp from the web app.');
829
+ }
830
+ await nativeAdapters.openUrl(connectUrl);
772
831
  } catch (error) {
773
832
  showAlert(nativeAdapters, 'WhatsApp setup failed', getErrorMessage(error));
774
833
  } finally {
775
- setConnectingChannelId(null);
834
+ if (activeAgentIdRef.current === agentId) setConnectingChannelId(null);
776
835
  }
777
836
  }, [nativeAdapters, resolveRuntimeToken, superagentService]);
778
837
 
@@ -781,12 +840,14 @@ export function useSuperagentRuntime({
781
840
  try {
782
841
  const runtimeToken = await resolveRuntimeToken(agentId);
783
842
  const telegram = await superagentService.setupTelegram(agentId, runtimeToken, token);
784
- setChannelStatus((current) => ({
785
- ...current,
786
- telegram,
787
- }));
843
+ if (activeAgentIdRef.current === agentId) {
844
+ setChannelStatus((current) => ({
845
+ ...current,
846
+ telegram,
847
+ }));
848
+ }
788
849
  } finally {
789
- setConnectingChannelId(null);
850
+ if (activeAgentIdRef.current === agentId) setConnectingChannelId(null);
790
851
  }
791
852
  }, [resolveRuntimeToken, superagentService]);
792
853
 
@@ -805,14 +866,16 @@ export function useSuperagentRuntime({
805
866
  try {
806
867
  const token = await resolveRuntimeToken(agentId);
807
868
  await superagentService.disconnectTelegram(agentId, token);
808
- setChannelStatus((current) => ({
809
- ...current,
810
- telegram: {connected: false},
811
- }));
869
+ if (activeAgentIdRef.current === agentId) {
870
+ setChannelStatus((current) => ({
871
+ ...current,
872
+ telegram: {connected: false},
873
+ }));
874
+ }
812
875
  } catch (error) {
813
876
  showAlert(nativeAdapters, 'Telegram disconnect failed', getErrorMessage(error));
814
877
  } finally {
815
- setConnectingChannelId(null);
878
+ if (activeAgentIdRef.current === agentId) setConnectingChannelId(null);
816
879
  }
817
880
  }, [nativeAdapters, resolveRuntimeToken, superagentService]);
818
881
 
@@ -821,18 +884,20 @@ export function useSuperagentRuntime({
821
884
  try {
822
885
  const token = await resolveRuntimeToken(agentId);
823
886
  const activation = await superagentService.generateLineCode(agentId, token);
824
- setChannelStatus((current) => ({
825
- ...current,
826
- line: {
827
- ...current.line,
828
- activation,
829
- connected: false,
830
- },
831
- }));
887
+ if (activeAgentIdRef.current === agentId) {
888
+ setChannelStatus((current) => ({
889
+ ...current,
890
+ line: {
891
+ ...current.line,
892
+ activation,
893
+ connected: false,
894
+ },
895
+ }));
896
+ }
832
897
  } catch (error) {
833
898
  showAlert(nativeAdapters, 'LINE setup failed', getErrorMessage(error));
834
899
  } finally {
835
- setConnectingChannelId(null);
900
+ if (activeAgentIdRef.current === agentId) setConnectingChannelId(null);
836
901
  }
837
902
  }, [nativeAdapters, resolveRuntimeToken, superagentService]);
838
903
 
@@ -841,20 +906,22 @@ export function useSuperagentRuntime({
841
906
  try {
842
907
  const token = await resolveRuntimeToken(agentId);
843
908
  const activation = await superagentService.generateIMessageCode(agentId, token);
844
- setChannelStatus((current) => ({
845
- ...current,
846
- imessage: {
847
- ...current.imessage,
848
- activation,
849
- connected: current.imessage?.connected ?? false,
850
- },
851
- }));
909
+ if (activeAgentIdRef.current === agentId) {
910
+ setChannelStatus((current) => ({
911
+ ...current,
912
+ imessage: {
913
+ ...current.imessage,
914
+ activation,
915
+ connected: current.imessage?.connected ?? false,
916
+ },
917
+ }));
918
+ }
852
919
  return activation;
853
920
  } catch (error) {
854
921
  showAlert(nativeAdapters, 'iMessage setup failed', getErrorMessage(error));
855
922
  throw error;
856
923
  } finally {
857
- setConnectingChannelId(null);
924
+ if (activeAgentIdRef.current === agentId) setConnectingChannelId(null);
858
925
  }
859
926
  }, [nativeAdapters, resolveRuntimeToken, superagentService]);
860
927
 
@@ -873,20 +940,25 @@ export function useSuperagentRuntime({
873
940
  try {
874
941
  const token = await resolveRuntimeToken(agentId);
875
942
  const imessage = await superagentService.disconnectIMessage(agentId, token);
876
- setChannelStatus((current) => ({
877
- ...current,
878
- imessage,
879
- }));
943
+ if (activeAgentIdRef.current === agentId) {
944
+ setChannelStatus((current) => ({
945
+ ...current,
946
+ imessage,
947
+ }));
948
+ }
880
949
  } catch (error) {
881
950
  showAlert(nativeAdapters, 'iMessage disconnect failed', getErrorMessage(error));
882
951
  } finally {
883
- setConnectingChannelId(null);
952
+ if (activeAgentIdRef.current === agentId) setConnectingChannelId(null);
884
953
  }
885
954
  }, [nativeAdapters, resolveRuntimeToken, superagentService]);
886
955
 
887
956
  const onOpenIMessage = useCallback(async ({code, phoneNumber}: SuperagentIMessageCodeShareInput) => {
888
957
  try {
889
- await nativeAdapters.openUrl?.(buildIMessageUrl(phoneNumber, code));
958
+ if (!nativeAdapters.openUrl) {
959
+ throw new Error('This app cannot open Messages. Use the web app to share the iMessage code.');
960
+ }
961
+ await nativeAdapters.openUrl(buildIMessageUrl(phoneNumber, code));
890
962
  } catch (error) {
891
963
  showAlert(nativeAdapters, 'iMessage link unavailable', getErrorMessage(error));
892
964
  }
@@ -901,7 +973,11 @@ export function useSuperagentRuntime({
901
973
  }, [nativeAdapters]);
902
974
 
903
975
  const onShareLineCode = useCallback(async ({addFriendUrl, code}: SuperagentLineCodeShareInput) => {
904
- await nativeAdapters.share?.({
976
+ if (!nativeAdapters.share) {
977
+ showAlert(nativeAdapters, 'Sharing unavailable', 'This app cannot share the activation code. Copy it manually instead.');
978
+ return;
979
+ }
980
+ await nativeAdapters.share({
905
981
  message: `LINE activation code: ${code}\n${addFriendUrl}`,
906
982
  title: 'LINE activation code',
907
983
  url: addFriendUrl,
@@ -909,7 +985,11 @@ export function useSuperagentRuntime({
909
985
  }, [nativeAdapters]);
910
986
 
911
987
  const onShareIMessageCode = useCallback(async ({code, phoneNumber}: SuperagentIMessageCodeShareInput) => {
912
- await nativeAdapters.share?.({
988
+ if (!nativeAdapters.share) {
989
+ showAlert(nativeAdapters, 'Sharing unavailable', 'This app cannot share the activation code. Copy it manually instead.');
990
+ return;
991
+ }
992
+ await nativeAdapters.share({
913
993
  message: `Text ${code} to ${phoneNumber} to connect this Superagent on iMessage.`,
914
994
  title: 'iMessage activation code',
915
995
  url: buildIMessageUrl(phoneNumber, code),
@@ -944,26 +1024,38 @@ export function useSuperagentRuntime({
944
1024
  connectorFlowRef.current = null;
945
1025
  setConnectingConnectorId(null);
946
1026
  await loadConnectors(agentId);
947
- return true;
1027
+ // Return the connection_id (string) so the connector tool-approval can
1028
+ // submit it; fall back to `true` when the backend omits it.
1029
+ return connection.connection_id ?? true;
948
1030
  }
949
1031
 
950
1032
  if (!connection.redirect_url || !connection.connection_id) {
951
1033
  throw new Error('The backend did not return an authorization URL for this connector.');
952
1034
  }
953
1035
 
954
- await nativeAdapters.openUrl?.(connection.redirect_url);
955
- await waitForConnectorAuthorization(superagentService, agentId, connectorId, connection.connection_id, flow);
1036
+ if (!nativeAdapters.openUrl) {
1037
+ // Without a URL opener the browser never launches, so polling would just
1038
+ // time out after ~2 minutes. Fail immediately with an actionable error.
1039
+ throw new Error('This app cannot open the authorization page. Connect this integration from the web app.');
1040
+ }
1041
+
1042
+ await nativeAdapters.openUrl(connection.redirect_url);
1043
+ const connected = await waitForConnectorAuthorization(superagentService, agentId, connectorId, connection.connection_id, flow);
956
1044
 
957
- if (!flow.cancelled) {
1045
+ // Only clear shared state if this flow is still the active one — a newer
1046
+ // connect may have superseded it (and owns connectorFlowRef now).
1047
+ if (connectorFlowRef.current === flow) {
958
1048
  connectorFlowRef.current = null;
959
1049
  setConnectingConnectorId(null);
1050
+ }
1051
+ if (connected) {
960
1052
  await loadConnectors(agentId);
961
- return true;
962
1053
  }
963
-
964
- return false;
1054
+ // On success return the connection_id so the connector tool-approval can
1055
+ // submit it for backend verification; `false` on failure.
1056
+ return connected ? connection.connection_id : false;
965
1057
  } catch (error) {
966
- if (!flow.cancelled) {
1058
+ if (connectorFlowRef.current === flow) {
967
1059
  connectorFlowRef.current = null;
968
1060
  setConnectingConnectorId(null);
969
1061
  showAlert(nativeAdapters, 'Connector failed', getErrorMessage(error));
@@ -1022,6 +1114,7 @@ export function useSuperagentRuntime({
1022
1114
  }, [loadConnectors, nativeAdapters, superagentService]);
1023
1115
 
1024
1116
  return {
1117
+ activeAgentId,
1025
1118
  agents,
1026
1119
  apiClient,
1027
1120
  availableConnectors,
@@ -1033,7 +1126,12 @@ export function useSuperagentRuntime({
1033
1126
  connectingConnectorId,
1034
1127
  connectedConnectors,
1035
1128
  currentRoute,
1129
+ // Also expose as initialRoute, the prop SuperagentHomeScreen actually consumes,
1130
+ // so spreading the runtime opens on the deep-linked agent (initialAgentId)
1131
+ // instead of defaulting to the home route.
1132
+ initialRoute: currentRoute,
1036
1133
  currentUserAvatarUrl: config.currentUserAvatarUrl,
1134
+ currentUserId: config.currentUserId,
1037
1135
  currentUserName: config.currentUserName,
1038
1136
  fileLoadError,
1039
1137
  fileLoadFailed,
@@ -1086,7 +1184,10 @@ export function useSuperagentRuntime({
1086
1184
  onShareAgentLink,
1087
1185
  onShareIMessageCode,
1088
1186
  onShareLineCode,
1089
- onStartLiveVoice,
1187
+ // Only expose Live Voice when the native audio adapter is actually installed;
1188
+ // otherwise the composer would prefer it and fail on tap ("audio callbacks are
1189
+ // not installed") instead of falling back to onStartVoiceInput.
1190
+ onStartLiveVoice: nativeAdapters.liveVoiceAudio?.startAudioCapture ? onStartLiveVoice : undefined,
1090
1191
  onSetupTelegram,
1091
1192
  onToggleAutomation,
1092
1193
  onUpdateAgentModel,
@@ -1103,25 +1204,32 @@ async function waitForConnectorAuthorization(
1103
1204
  connectorId: string,
1104
1205
  connectionId: string,
1105
1206
  flow: ConnectorFlow,
1106
- ) {
1207
+ ): Promise<boolean> {
1208
+ // The connection status (scoped to this flow's connectionId) is the
1209
+ // authoritative source of truth — not a global callback flag, which can't be
1210
+ // attributed to a specific flow. Returns whether the connector ended up ACTIVE.
1211
+ const isActive = async () =>
1212
+ (await superagentService.getConnectorConnectionStatus(agentId, connectorId, connectionId)) === 'ACTIVE';
1213
+
1107
1214
  const maxAttempts = 40;
1108
1215
  for (let attempt = 0; attempt < maxAttempts; attempt++) {
1109
1216
  if (flow.cancelled) {
1110
- return;
1217
+ // Cancelled — but OAuth may have already completed; confirm with the
1218
+ // authoritative status before reporting not-connected.
1219
+ return isActive().catch(() => false);
1111
1220
  }
1112
1221
 
1113
1222
  await delay(3000);
1114
- if (flow.cancelled) {
1115
- return;
1116
- }
1117
1223
 
1118
1224
  const status = await superagentService.getConnectorConnectionStatus(agentId, connectorId, connectionId);
1119
1225
  if (status === 'ACTIVE') {
1120
- return;
1226
+ return true;
1121
1227
  }
1122
1228
  if (status === 'FAILED') {
1123
1229
  throw new Error('OAuth connection failed.');
1124
1230
  }
1231
+ // If the user cancelled during the delay, the next iteration's top-of-loop
1232
+ // check re-confirms via the authoritative status before returning.
1125
1233
  }
1126
1234
 
1127
1235
  throw new Error('Connection timed out after 2 minutes.');
@@ -1138,26 +1246,55 @@ async function openAllowedExternalUrl(
1138
1246
  return;
1139
1247
  }
1140
1248
 
1249
+ if (!nativeAdapters.openUrl) {
1250
+ // No URL opener: surface it instead of passing the host check and then
1251
+ // silently doing nothing.
1252
+ showAlert(nativeAdapters, fallbackMessage, 'This app cannot open external links. Use the web app instead.');
1253
+ return;
1254
+ }
1255
+
1141
1256
  try {
1142
- await nativeAdapters.openUrl?.(url);
1257
+ await nativeAdapters.openUrl(url);
1143
1258
  } catch (error) {
1144
1259
  showAlert(nativeAdapters, fallbackMessage, getErrorMessage(error));
1145
1260
  }
1146
1261
  }
1147
1262
 
1148
1263
  function showAlert(nativeAdapters: SuperagentNativeRuntimeAdapters, title: string, message?: string) {
1149
- nativeAdapters.alert?.(title, message);
1264
+ if (nativeAdapters.alert) {
1265
+ nativeAdapters.alert(title, message);
1266
+ return;
1267
+ }
1268
+ // No host alert adapter — fall back to React Native's Alert (as confirmAction
1269
+ // does) so connector/channel/file/model errors aren't silently swallowed.
1270
+ Alert.alert(title, message);
1150
1271
  }
1151
1272
 
1152
1273
  async function confirmAction(
1153
1274
  nativeAdapters: SuperagentNativeRuntimeAdapters,
1154
1275
  input: Parameters<NonNullable<SuperagentNativeRuntimeAdapters['confirm']>>[0],
1155
1276
  ) {
1156
- if (!nativeAdapters.confirm) {
1157
- return true;
1277
+ if (nativeAdapters.confirm) {
1278
+ return nativeAdapters.confirm(input);
1158
1279
  }
1159
1280
 
1160
- return nativeAdapters.confirm(input);
1281
+ // No host confirm adapter — fall back to a native prompt so destructive actions
1282
+ // still require explicit confirmation instead of silently proceeding.
1283
+ return new Promise<boolean>((resolve) => {
1284
+ Alert.alert(
1285
+ input.title,
1286
+ input.message,
1287
+ [
1288
+ { onPress: () => resolve(false), style: 'cancel', text: 'Cancel' },
1289
+ {
1290
+ onPress: () => resolve(true),
1291
+ style: input.destructive ? 'destructive' : 'default',
1292
+ text: input.confirmText ?? 'Confirm',
1293
+ },
1294
+ ],
1295
+ { cancelable: true, onDismiss: () => resolve(false) },
1296
+ );
1297
+ });
1161
1298
  }
1162
1299
 
1163
1300
  function buildWebUrl(baseUrl: string, path: string) {