@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,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
- if (agentId === activeAgentId && runtimeAuthToken) {
149
- return runtimeAuthToken;
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
- if (agentId === activeAgentId) {
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
- }, [activeAgentId, runtimeAuthToken, superagentService]);
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
- if (event.status === 'success') {
231
- flow.cancelled = true;
232
- connectorFlowRef.current = null;
233
- setConnectingConnectorId(null);
234
- await loadConnectors(flow.agentId);
235
- return;
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
- await loadConnectors(flow.agentId);
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
- nativeAdapters.openWebUrl?.(buildWebUrl(config.webUrl ?? config.baseUrl, `/remix-app/${encodeURIComponent(agentId)}?clone_history=true`));
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
- await superagentService.writeSandboxFile(agentId, file.name, file.content);
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 files.map(file => ({
598
- path: file.name
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
- setChannelStatus(current => ({
630
- ...current,
631
- whatsapp: {
632
- ...current.whatsapp,
633
- connectUrl
634
- }
635
- }));
636
- await nativeAdapters.openUrl?.(connectUrl);
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
- setChannelStatus(current => ({
652
- ...current,
653
- telegram
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
- setChannelStatus(current => ({
676
- ...current,
677
- telegram: {
678
- connected: false
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
- setChannelStatus(current => ({
695
- ...current,
696
- line: {
697
- ...current.line,
698
- activation,
699
- connected: false
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
- setChannelStatus(current => ({
716
- ...current,
717
- imessage: {
718
- ...current.imessage,
719
- activation,
720
- connected: current.imessage?.connected ?? false
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
- setChannelStatus(current => ({
748
- ...current,
749
- imessage
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
- await nativeAdapters.openUrl?.(buildIMessageUrl(phoneNumber, code));
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
- await nativeAdapters.share?.({
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
- await nativeAdapters.share?.({
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
- return true;
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
- await nativeAdapters.openUrl?.(connection.redirect_url);
833
- await waitForConnectorAuthorization(superagentService, agentId, connectorId, connection.connection_id, flow);
834
- if (!flow.cancelled) {
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 false;
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 (!flow.cancelled) {
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
- onStartLiveVoice,
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
- return;
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?.(url);
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?.(title, message);
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 (!nativeAdapters.confirm) {
1014
- return true;
1137
+ if (nativeAdapters.confirm) {
1138
+ return nativeAdapters.confirm(input);
1015
1139
  }
1016
- return nativeAdapters.confirm(input);
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}`}`;