@base44/superagent-native 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +12 -20
- package/lib/commonjs/AgentSettingsPanel.js +155 -62
- package/lib/commonjs/AgentSettingsPanel.js.map +1 -1
- package/lib/commonjs/AgentSphereIcon.js +14 -118
- package/lib/commonjs/AgentSphereIcon.js.map +1 -1
- package/lib/commonjs/AttachmentPickerStatusModal.js +5 -4
- package/lib/commonjs/AttachmentPickerStatusModal.js.map +1 -1
- package/lib/commonjs/ChannelsPanel.js +66 -44
- package/lib/commonjs/ChannelsPanel.js.map +1 -1
- package/lib/commonjs/ConversationChat.js +38 -13
- package/lib/commonjs/ConversationChat.js.map +1 -1
- package/lib/commonjs/ConversationComposer.js +18 -13
- package/lib/commonjs/ConversationComposer.js.map +1 -1
- package/lib/commonjs/ConversationScreen.js +4 -0
- package/lib/commonjs/ConversationScreen.js.map +1 -1
- package/lib/commonjs/EditorDrawer.js +54 -24
- package/lib/commonjs/EditorDrawer.js.map +1 -1
- package/lib/commonjs/FilesPanel.js +56 -20
- package/lib/commonjs/FilesPanel.js.map +1 -1
- package/lib/commonjs/MarkdownText.js +1 -1
- package/lib/commonjs/MarkdownText.js.map +1 -1
- package/lib/commonjs/MessageActionBar.js +10 -3
- package/lib/commonjs/MessageActionBar.js.map +1 -1
- package/lib/commonjs/RenameAgentModal.js +2 -1
- package/lib/commonjs/RenameAgentModal.js.map +1 -1
- package/lib/commonjs/ShareAgentModal.js +11 -10
- package/lib/commonjs/ShareAgentModal.js.map +1 -1
- package/lib/commonjs/ShareAgentModal.styles.js +2 -2
- package/lib/commonjs/ShareAgentModal.styles.js.map +1 -1
- package/lib/commonjs/SuperagentHomeScreen.js +44 -12
- package/lib/commonjs/SuperagentHomeScreen.js.map +1 -1
- package/lib/commonjs/ToolApprovalCard.js +73 -15
- package/lib/commonjs/ToolApprovalCard.js.map +1 -1
- package/lib/commonjs/ToolCallSummary.js +19 -10
- package/lib/commonjs/ToolCallSummary.js.map +1 -1
- package/lib/commonjs/agentSphereAssets.js +327 -0
- package/lib/commonjs/agentSphereAssets.js.map +1 -0
- package/lib/commonjs/agentSphereStyles.js +3 -3
- package/lib/commonjs/agentSphereStyles.js.map +1 -1
- package/lib/commonjs/apiClient.js +7 -0
- package/lib/commonjs/apiClient.js.map +1 -1
- package/lib/commonjs/attachmentUpload.js +2 -1
- package/lib/commonjs/attachmentUpload.js.map +1 -1
- package/lib/commonjs/composerStyles.js +2 -2
- package/lib/commonjs/composerStyles.js.map +1 -1
- package/lib/commonjs/connectorBrandIcons.generated.js +625 -0
- package/lib/commonjs/connectorBrandIcons.generated.js.map +1 -0
- package/lib/commonjs/connectorBrandIcons.js +3 -55
- package/lib/commonjs/connectorBrandIcons.js.map +1 -1
- package/lib/commonjs/connectorCatalog.js +19 -1
- package/lib/commonjs/connectorCatalog.js.map +1 -1
- package/lib/commonjs/conversationParts.js +5 -4
- package/lib/commonjs/conversationParts.js.map +1 -1
- package/lib/commonjs/conversationRuntime.js +152 -9
- package/lib/commonjs/conversationRuntime.js.map +1 -1
- package/lib/commonjs/conversationStyles.js +2 -1
- package/lib/commonjs/conversationStyles.js.map +1 -1
- package/lib/commonjs/editorShellStyles.js +6 -2
- package/lib/commonjs/editorShellStyles.js.map +1 -1
- package/lib/commonjs/fileTreeUtils.js +7 -0
- package/lib/commonjs/fileTreeUtils.js.map +1 -1
- package/lib/commonjs/index.js +7 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/markdownStyles.js +2 -2
- package/lib/commonjs/markdownStyles.js.map +1 -1
- package/lib/commonjs/messageActionStyles.js +2 -2
- package/lib/commonjs/messageActionStyles.js.map +1 -1
- package/lib/commonjs/realtimeClient.js +4 -1
- package/lib/commonjs/realtimeClient.js.map +1 -1
- package/lib/commonjs/renameAgentModalStyles.js +2 -2
- package/lib/commonjs/renameAgentModalStyles.js.map +1 -1
- package/lib/commonjs/screenParts.js +24 -41
- package/lib/commonjs/screenParts.js.map +1 -1
- package/lib/commonjs/styles.js +32 -21
- package/lib/commonjs/styles.js.map +1 -1
- package/lib/commonjs/superagentApiClient.js +63 -18
- package/lib/commonjs/superagentApiClient.js.map +1 -1
- package/lib/commonjs/theme.js +249 -0
- package/lib/commonjs/theme.js.map +1 -0
- package/lib/commonjs/useSuperagentConversation.js +240 -44
- package/lib/commonjs/useSuperagentConversation.js.map +1 -1
- package/lib/commonjs/useSuperagentRuntime.js +245 -105
- package/lib/commonjs/useSuperagentRuntime.js.map +1 -1
- package/lib/module/AgentSettingsPanel.js +157 -64
- package/lib/module/AgentSettingsPanel.js.map +1 -1
- package/lib/module/AgentSphereIcon.js +15 -118
- package/lib/module/AgentSphereIcon.js.map +1 -1
- package/lib/module/AttachmentPickerStatusModal.js +6 -5
- package/lib/module/AttachmentPickerStatusModal.js.map +1 -1
- package/lib/module/ChannelsPanel.js +67 -45
- package/lib/module/ChannelsPanel.js.map +1 -1
- package/lib/module/ConversationChat.js +38 -13
- package/lib/module/ConversationChat.js.map +1 -1
- package/lib/module/ConversationComposer.js +18 -13
- package/lib/module/ConversationComposer.js.map +1 -1
- package/lib/module/ConversationScreen.js +4 -0
- package/lib/module/ConversationScreen.js.map +1 -1
- package/lib/module/EditorDrawer.js +55 -25
- package/lib/module/EditorDrawer.js.map +1 -1
- package/lib/module/FilesPanel.js +56 -20
- package/lib/module/FilesPanel.js.map +1 -1
- package/lib/module/MarkdownText.js +1 -1
- package/lib/module/MarkdownText.js.map +1 -1
- package/lib/module/MessageActionBar.js +10 -3
- package/lib/module/MessageActionBar.js.map +1 -1
- package/lib/module/RenameAgentModal.js +2 -1
- package/lib/module/RenameAgentModal.js.map +1 -1
- package/lib/module/ShareAgentModal.js +11 -10
- package/lib/module/ShareAgentModal.js.map +1 -1
- package/lib/module/ShareAgentModal.styles.js +2 -2
- package/lib/module/ShareAgentModal.styles.js.map +1 -1
- package/lib/module/SuperagentHomeScreen.js +45 -13
- package/lib/module/SuperagentHomeScreen.js.map +1 -1
- package/lib/module/ToolApprovalCard.js +73 -15
- package/lib/module/ToolApprovalCard.js.map +1 -1
- package/lib/module/ToolCallSummary.js +19 -10
- package/lib/module/ToolCallSummary.js.map +1 -1
- package/lib/module/agentSphereAssets.js +323 -0
- package/lib/module/agentSphereAssets.js.map +1 -0
- package/lib/module/agentSphereStyles.js +3 -3
- package/lib/module/agentSphereStyles.js.map +1 -1
- package/lib/module/apiClient.js +7 -0
- package/lib/module/apiClient.js.map +1 -1
- package/lib/module/attachmentUpload.js +2 -1
- package/lib/module/attachmentUpload.js.map +1 -1
- package/lib/module/composerStyles.js +2 -2
- package/lib/module/composerStyles.js.map +1 -1
- package/lib/module/connectorBrandIcons.generated.js +621 -0
- package/lib/module/connectorBrandIcons.generated.js.map +1 -0
- package/lib/module/connectorBrandIcons.js +1 -53
- package/lib/module/connectorBrandIcons.js.map +1 -1
- package/lib/module/connectorCatalog.js +17 -0
- package/lib/module/connectorCatalog.js.map +1 -1
- package/lib/module/conversationParts.js +5 -4
- package/lib/module/conversationParts.js.map +1 -1
- package/lib/module/conversationRuntime.js +149 -9
- package/lib/module/conversationRuntime.js.map +1 -1
- package/lib/module/conversationStyles.js +3 -2
- package/lib/module/conversationStyles.js.map +1 -1
- package/lib/module/editorShellStyles.js +6 -2
- package/lib/module/editorShellStyles.js.map +1 -1
- package/lib/module/fileTreeUtils.js +6 -0
- package/lib/module/fileTreeUtils.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/markdownStyles.js +2 -2
- package/lib/module/markdownStyles.js.map +1 -1
- package/lib/module/messageActionStyles.js +2 -2
- package/lib/module/messageActionStyles.js.map +1 -1
- package/lib/module/realtimeClient.js +4 -1
- package/lib/module/realtimeClient.js.map +1 -1
- package/lib/module/renameAgentModalStyles.js +2 -2
- package/lib/module/renameAgentModalStyles.js.map +1 -1
- package/lib/module/screenParts.js +25 -42
- package/lib/module/screenParts.js.map +1 -1
- package/lib/module/styles.js +32 -21
- package/lib/module/styles.js.map +1 -1
- package/lib/module/superagentApiClient.js +63 -18
- package/lib/module/superagentApiClient.js.map +1 -1
- package/lib/module/theme.js +239 -0
- package/lib/module/theme.js.map +1 -0
- package/lib/module/useSuperagentConversation.js +242 -46
- package/lib/module/useSuperagentConversation.js.map +1 -1
- package/lib/module/useSuperagentRuntime.js +246 -106
- package/lib/module/useSuperagentRuntime.js.map +1 -1
- package/lib/typescript/commonjs/AgentSettingsPanel.d.ts.map +1 -1
- package/lib/typescript/commonjs/AgentSphereIcon.d.ts.map +1 -1
- package/lib/typescript/commonjs/AttachmentPickerStatusModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/ChannelsPanel.d.ts.map +1 -1
- package/lib/typescript/commonjs/ConversationChat.d.ts +1 -1
- package/lib/typescript/commonjs/ConversationChat.d.ts.map +1 -1
- package/lib/typescript/commonjs/ConversationComposer.d.ts.map +1 -1
- package/lib/typescript/commonjs/ConversationMessageList.d.ts +1 -1
- package/lib/typescript/commonjs/ConversationMessageList.d.ts.map +1 -1
- package/lib/typescript/commonjs/ConversationScreen.d.ts +2 -1
- package/lib/typescript/commonjs/ConversationScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/EditorDrawer.d.ts +1 -1
- package/lib/typescript/commonjs/EditorDrawer.d.ts.map +1 -1
- package/lib/typescript/commonjs/FilesPanel.d.ts.map +1 -1
- package/lib/typescript/commonjs/RenameAgentModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/ShareAgentModal.d.ts.map +1 -1
- package/lib/typescript/commonjs/ShareAgentModal.styles.d.ts.map +1 -1
- package/lib/typescript/commonjs/SuperagentHomeScreen.d.ts.map +1 -1
- package/lib/typescript/commonjs/ToolApprovalCard.d.ts +3 -3
- package/lib/typescript/commonjs/ToolApprovalCard.d.ts.map +1 -1
- package/lib/typescript/commonjs/ToolCallSummary.d.ts +1 -1
- package/lib/typescript/commonjs/ToolCallSummary.d.ts.map +1 -1
- package/lib/typescript/commonjs/agentSphereAssets.d.ts +2 -0
- package/lib/typescript/commonjs/agentSphereAssets.d.ts.map +1 -0
- package/lib/typescript/commonjs/agentSphereStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/apiClient.d.ts.map +1 -1
- package/lib/typescript/commonjs/composerStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/connectorBrandIcons.d.ts.map +1 -1
- package/lib/typescript/commonjs/connectorBrandIcons.generated.d.ts +2 -0
- package/lib/typescript/commonjs/connectorBrandIcons.generated.d.ts.map +1 -0
- package/lib/typescript/commonjs/connectorCatalog.d.ts +2 -0
- package/lib/typescript/commonjs/connectorCatalog.d.ts.map +1 -1
- package/lib/typescript/commonjs/conversationParts.d.ts +1 -1
- package/lib/typescript/commonjs/conversationParts.d.ts.map +1 -1
- package/lib/typescript/commonjs/conversationRuntime.d.ts +9 -3
- package/lib/typescript/commonjs/conversationRuntime.d.ts.map +1 -1
- package/lib/typescript/commonjs/conversationStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/editorShellStyles.d.ts +4 -0
- package/lib/typescript/commonjs/editorShellStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/fileTreeUtils.d.ts +1 -0
- package/lib/typescript/commonjs/fileTreeUtils.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +2 -0
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/markdownStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/messageActionStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/realtimeClient.d.ts.map +1 -1
- package/lib/typescript/commonjs/renameAgentModalStyles.d.ts.map +1 -1
- package/lib/typescript/commonjs/screenParts.d.ts +1 -1
- package/lib/typescript/commonjs/screenParts.d.ts.map +1 -1
- package/lib/typescript/commonjs/styles.d.ts +20 -11
- package/lib/typescript/commonjs/styles.d.ts.map +1 -1
- package/lib/typescript/commonjs/superagentApiClient.d.ts +2 -1
- package/lib/typescript/commonjs/superagentApiClient.d.ts.map +1 -1
- package/lib/typescript/commonjs/theme.d.ts +36 -0
- package/lib/typescript/commonjs/theme.d.ts.map +1 -0
- package/lib/typescript/commonjs/types.d.ts +17 -2
- package/lib/typescript/commonjs/types.d.ts.map +1 -1
- package/lib/typescript/commonjs/useSuperagentConversation.d.ts +3 -2
- package/lib/typescript/commonjs/useSuperagentConversation.d.ts.map +1 -1
- package/lib/typescript/commonjs/useSuperagentRuntime.d.ts +5 -2
- package/lib/typescript/commonjs/useSuperagentRuntime.d.ts.map +1 -1
- package/lib/typescript/module/AgentSettingsPanel.d.ts.map +1 -1
- package/lib/typescript/module/AgentSphereIcon.d.ts.map +1 -1
- package/lib/typescript/module/AttachmentPickerStatusModal.d.ts.map +1 -1
- package/lib/typescript/module/ChannelsPanel.d.ts.map +1 -1
- package/lib/typescript/module/ConversationChat.d.ts +1 -1
- package/lib/typescript/module/ConversationChat.d.ts.map +1 -1
- package/lib/typescript/module/ConversationComposer.d.ts.map +1 -1
- package/lib/typescript/module/ConversationMessageList.d.ts +1 -1
- package/lib/typescript/module/ConversationMessageList.d.ts.map +1 -1
- package/lib/typescript/module/ConversationScreen.d.ts +2 -1
- package/lib/typescript/module/ConversationScreen.d.ts.map +1 -1
- package/lib/typescript/module/EditorDrawer.d.ts +1 -1
- package/lib/typescript/module/EditorDrawer.d.ts.map +1 -1
- package/lib/typescript/module/FilesPanel.d.ts.map +1 -1
- package/lib/typescript/module/RenameAgentModal.d.ts.map +1 -1
- package/lib/typescript/module/ShareAgentModal.d.ts.map +1 -1
- package/lib/typescript/module/ShareAgentModal.styles.d.ts.map +1 -1
- package/lib/typescript/module/SuperagentHomeScreen.d.ts.map +1 -1
- package/lib/typescript/module/ToolApprovalCard.d.ts +3 -3
- package/lib/typescript/module/ToolApprovalCard.d.ts.map +1 -1
- package/lib/typescript/module/ToolCallSummary.d.ts +1 -1
- package/lib/typescript/module/ToolCallSummary.d.ts.map +1 -1
- package/lib/typescript/module/agentSphereAssets.d.ts +2 -0
- package/lib/typescript/module/agentSphereAssets.d.ts.map +1 -0
- package/lib/typescript/module/agentSphereStyles.d.ts.map +1 -1
- package/lib/typescript/module/apiClient.d.ts.map +1 -1
- package/lib/typescript/module/composerStyles.d.ts.map +1 -1
- package/lib/typescript/module/connectorBrandIcons.d.ts.map +1 -1
- package/lib/typescript/module/connectorBrandIcons.generated.d.ts +2 -0
- package/lib/typescript/module/connectorBrandIcons.generated.d.ts.map +1 -0
- package/lib/typescript/module/connectorCatalog.d.ts +2 -0
- package/lib/typescript/module/connectorCatalog.d.ts.map +1 -1
- package/lib/typescript/module/conversationParts.d.ts +1 -1
- package/lib/typescript/module/conversationParts.d.ts.map +1 -1
- package/lib/typescript/module/conversationRuntime.d.ts +9 -3
- package/lib/typescript/module/conversationRuntime.d.ts.map +1 -1
- package/lib/typescript/module/conversationStyles.d.ts.map +1 -1
- package/lib/typescript/module/editorShellStyles.d.ts +4 -0
- package/lib/typescript/module/editorShellStyles.d.ts.map +1 -1
- package/lib/typescript/module/fileTreeUtils.d.ts +1 -0
- package/lib/typescript/module/fileTreeUtils.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +2 -0
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/markdownStyles.d.ts.map +1 -1
- package/lib/typescript/module/messageActionStyles.d.ts.map +1 -1
- package/lib/typescript/module/realtimeClient.d.ts.map +1 -1
- package/lib/typescript/module/renameAgentModalStyles.d.ts.map +1 -1
- package/lib/typescript/module/screenParts.d.ts +1 -1
- package/lib/typescript/module/screenParts.d.ts.map +1 -1
- package/lib/typescript/module/styles.d.ts +20 -11
- package/lib/typescript/module/styles.d.ts.map +1 -1
- package/lib/typescript/module/superagentApiClient.d.ts +2 -1
- package/lib/typescript/module/superagentApiClient.d.ts.map +1 -1
- package/lib/typescript/module/theme.d.ts +36 -0
- package/lib/typescript/module/theme.d.ts.map +1 -0
- package/lib/typescript/module/types.d.ts +17 -2
- package/lib/typescript/module/types.d.ts.map +1 -1
- package/lib/typescript/module/useSuperagentConversation.d.ts +3 -2
- package/lib/typescript/module/useSuperagentConversation.d.ts.map +1 -1
- package/lib/typescript/module/useSuperagentRuntime.d.ts +5 -2
- package/lib/typescript/module/useSuperagentRuntime.d.ts.map +1 -1
- package/package.json +13 -11
- package/src/AgentSettingsPanel.tsx +146 -58
- package/src/AgentSphereIcon.tsx +11 -62
- package/src/AttachmentPickerStatusModal.tsx +6 -5
- package/src/ChannelsPanel.tsx +59 -39
- package/src/ConversationChat.tsx +49 -12
- package/src/ConversationComposer.tsx +18 -12
- package/src/ConversationMessageList.tsx +1 -1
- package/src/ConversationScreen.tsx +5 -0
- package/src/EditorDrawer.tsx +66 -41
- package/src/FilesPanel.tsx +48 -20
- package/src/MarkdownText.tsx +1 -1
- package/src/MessageActionBar.tsx +9 -3
- package/src/RenameAgentModal.tsx +2 -1
- package/src/ShareAgentModal.styles.ts +2 -1
- package/src/ShareAgentModal.tsx +9 -8
- package/src/SuperagentHomeScreen.tsx +45 -10
- package/src/ToolApprovalCard.tsx +83 -15
- package/src/ToolCallSummary.tsx +22 -13
- package/src/agentSphereAssets.ts +325 -0
- package/src/agentSphereStyles.ts +3 -2
- package/src/apiClient.ts +7 -0
- package/src/attachmentUpload.ts +2 -1
- package/src/composerStyles.ts +2 -1
- package/src/connectorBrandIcons.generated.ts +618 -0
- package/src/connectorBrandIcons.tsx +1 -53
- package/src/connectorCatalog.ts +24 -0
- package/src/conversationParts.tsx +6 -5
- package/src/conversationRuntime.ts +166 -11
- package/src/conversationStyles.ts +2 -1
- package/src/editorShellStyles.ts +6 -1
- package/src/fileTreeUtils.ts +13 -0
- package/src/index.ts +2 -0
- package/src/markdownStyles.ts +2 -1
- package/src/messageActionStyles.ts +2 -1
- package/src/realtimeClient.ts +7 -1
- package/src/renameAgentModalStyles.ts +2 -1
- package/src/screenParts.tsx +17 -29
- package/src/styles.ts +25 -16
- package/src/superagentApiClient.ts +68 -18
- package/src/theme.ts +254 -0
- package/src/types.ts +22 -2
- package/src/useSuperagentConversation.ts +247 -45
- package/src/useSuperagentRuntime.ts +244 -107
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { MESSAGES_PAGE_SIZE } from './constants';
|
|
4
4
|
import {
|
|
5
5
|
countAssistantResponses,
|
|
6
6
|
createErrorMessage,
|
|
7
7
|
createUserMessage,
|
|
8
8
|
getMessageCursor,
|
|
9
9
|
hasNewAssistantResponse,
|
|
10
|
+
hasRunningToolCall,
|
|
10
11
|
isQueuedResponse,
|
|
11
12
|
isVisibleMessage,
|
|
13
|
+
mergeConversationSnapshot,
|
|
12
14
|
mergeMessage,
|
|
13
15
|
normalizeMessages,
|
|
14
16
|
pollConversation,
|
|
17
|
+
pollQueuedSend,
|
|
15
18
|
refreshConversation,
|
|
16
19
|
sendWithFallback,
|
|
17
20
|
} from './conversationRuntime';
|
|
@@ -23,6 +26,7 @@ type UseConversationParams = {
|
|
|
23
26
|
agentId: string;
|
|
24
27
|
apiClient?: SuperagentNativeClient;
|
|
25
28
|
realtimeClient?: SuperagentRealtimeClient;
|
|
29
|
+
currentUserId?: string | null;
|
|
26
30
|
fallbackMessages: SuperagentMessage[];
|
|
27
31
|
fallbackSending: boolean;
|
|
28
32
|
onAgentMessageDone?: () => Promise<void> | void;
|
|
@@ -34,6 +38,7 @@ export function useSuperagentConversation({
|
|
|
34
38
|
agentId,
|
|
35
39
|
apiClient,
|
|
36
40
|
realtimeClient,
|
|
41
|
+
currentUserId,
|
|
37
42
|
fallbackMessages,
|
|
38
43
|
fallbackSending,
|
|
39
44
|
onAgentMessageDone,
|
|
@@ -48,6 +53,35 @@ export function useSuperagentConversation({
|
|
|
48
53
|
const [initError, setInitError] = useState<string | null>(null);
|
|
49
54
|
const [hasMoreMessages, setHasMoreMessages] = useState(false);
|
|
50
55
|
const sendGenerationRef = useRef(0);
|
|
56
|
+
const pollIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
|
|
57
|
+
const loadingPreviousRef = useRef(false);
|
|
58
|
+
const settleTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
59
|
+
const messagesRef = useRef(messages);
|
|
60
|
+
const onAgentMessageDoneRef = useRef(onAgentMessageDone);
|
|
61
|
+
const onConversationSettledRef = useRef(onConversationSettled);
|
|
62
|
+
|
|
63
|
+
useEffect(() => { messagesRef.current = messages; }, [messages]);
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
onAgentMessageDoneRef.current = onAgentMessageDone;
|
|
66
|
+
onConversationSettledRef.current = onConversationSettled;
|
|
67
|
+
}, [onAgentMessageDone, onConversationSettled]);
|
|
68
|
+
|
|
69
|
+
// Cancel any in-flight poll/settle timers — called on each new send and on unmount.
|
|
70
|
+
const clearPendingSettlers = useCallback(() => {
|
|
71
|
+
if (pollIntervalRef.current) {
|
|
72
|
+
clearInterval(pollIntervalRef.current);
|
|
73
|
+
pollIntervalRef.current = null;
|
|
74
|
+
}
|
|
75
|
+
if (settleTimeoutRef.current) {
|
|
76
|
+
clearTimeout(settleTimeoutRef.current);
|
|
77
|
+
settleTimeoutRef.current = null;
|
|
78
|
+
}
|
|
79
|
+
}, []);
|
|
80
|
+
|
|
81
|
+
// Clear any active poll interval / settle timeout when the hook unmounts.
|
|
82
|
+
useEffect(() => {
|
|
83
|
+
return () => clearPendingSettlers();
|
|
84
|
+
}, [clearPendingSettlers]);
|
|
51
85
|
|
|
52
86
|
useEffect(() => {
|
|
53
87
|
if (!apiClient) setMessages(fallbackMessages);
|
|
@@ -58,6 +92,13 @@ export function useSuperagentConversation({
|
|
|
58
92
|
const client = apiClient;
|
|
59
93
|
let cancelled = false;
|
|
60
94
|
|
|
95
|
+
// Clear the previous agent/client's conversation up front so a stale id or
|
|
96
|
+
// thread can't linger while the new one loads — or, if the reload fails, be
|
|
97
|
+
// shown or receive sends (conversationUnavailable only blocks with no id).
|
|
98
|
+
setConversationId(null);
|
|
99
|
+
setMessages([]);
|
|
100
|
+
setHasMoreMessages(false);
|
|
101
|
+
|
|
61
102
|
async function initConversation() {
|
|
62
103
|
setIsLoading(true);
|
|
63
104
|
setInitError(null);
|
|
@@ -74,7 +115,12 @@ export function useSuperagentConversation({
|
|
|
74
115
|
setHasMoreMessages(Boolean(page.has_more ?? page.hasMore));
|
|
75
116
|
|
|
76
117
|
if ((conversation.messages ?? []).length === 0) {
|
|
77
|
-
|
|
118
|
+
// Seed the intro via bootstrap-intro (hidden seed, no sandbox acquisition)
|
|
119
|
+
// instead of sending a visible "Hey!" through the full /messages path —
|
|
120
|
+
// opening an empty chat shouldn't stall on a cold sandbox or burn a
|
|
121
|
+
// tool-capable turn. The assistant intro arrives via realtime / a later
|
|
122
|
+
// refresh, so we don't block on it here.
|
|
123
|
+
await client.bootstrapIntro(conversation.id);
|
|
78
124
|
if (cancelled) return;
|
|
79
125
|
await refreshConversation(client, conversation.id, setMessages);
|
|
80
126
|
}
|
|
@@ -94,51 +140,113 @@ export function useSuperagentConversation({
|
|
|
94
140
|
|
|
95
141
|
return realtimeClient.subscribeToConversation(conversationId, {
|
|
96
142
|
onMessage(message) {
|
|
143
|
+
// Don't clear the sending/stop state on intermediate assistant messages
|
|
144
|
+
// (tool-call steps or streamed content arrive before the turn is done).
|
|
145
|
+
// The turn ends on `agent_done` (onAgentDone) or the 5s settle fallback.
|
|
97
146
|
setMessages((current) => mergeMessage(current, message));
|
|
98
|
-
if (message.role === 'assistant' && (message.content || message.toolCalls?.length || message.tool_calls?.length)) {
|
|
99
|
-
setIsSending(false);
|
|
100
|
-
}
|
|
101
147
|
},
|
|
102
148
|
onConversation(conversation) {
|
|
103
149
|
if (conversation.id !== conversationId) return;
|
|
104
|
-
|
|
150
|
+
const incoming = normalizeMessages(conversation.messages ?? []);
|
|
151
|
+
setMessages((current) => mergeConversationSnapshot(current, incoming));
|
|
105
152
|
},
|
|
106
|
-
onAgentDone() {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
153
|
+
onAgentDone(payload) {
|
|
154
|
+
// Shared conversations: the backend tags agent_done with the sender's
|
|
155
|
+
// platform user id. Ignore completions from OTHER collaborators so a
|
|
156
|
+
// teammate's finishing run doesn't clear THIS user's sending state or fire
|
|
157
|
+
// their completion callbacks early (matches the web client).
|
|
158
|
+
if (payload?.sender_platform_user_id && currentUserId && payload.sender_platform_user_id !== currentUserId) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
// Agent finished via realtime — cancel the 5s settle fallback so
|
|
162
|
+
// onConversationSettled doesn't also fire when the timer elapses.
|
|
163
|
+
if (settleTimeoutRef.current) {
|
|
164
|
+
clearTimeout(settleTimeoutRef.current);
|
|
165
|
+
settleTimeoutRef.current = null;
|
|
115
166
|
}
|
|
167
|
+
// Guard the busy-state clear against a newer send superseding this turn
|
|
168
|
+
// while we refresh/poll: only clear if no later send has started since
|
|
169
|
+
// (mirrors setSendingForCurrentSend in sendMessage).
|
|
170
|
+
const sendGeneration = sendGenerationRef.current;
|
|
171
|
+
const setSendingIfCurrent = (value: boolean) => {
|
|
172
|
+
if (sendGenerationRef.current === sendGeneration) setIsSending(value);
|
|
173
|
+
};
|
|
174
|
+
const settle = () => {
|
|
175
|
+
setSendingIfCurrent(false);
|
|
176
|
+
setQueuedMessages([]);
|
|
177
|
+
onAgentMessageDoneRef.current?.();
|
|
178
|
+
onConversationSettledRef.current?.();
|
|
179
|
+
};
|
|
180
|
+
if (!apiClient) {
|
|
181
|
+
settle();
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const handOffToPoll = (assistantCountBefore: number) => {
|
|
185
|
+
// Keep the busy state and let the bounded poll finish the turn (it
|
|
186
|
+
// retries refreshes and settles once no tool is running or the cap is
|
|
187
|
+
// hit), matching the no-realtime poll and 5s settle paths.
|
|
188
|
+
if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);
|
|
189
|
+
pollIntervalRef.current = pollConversation(
|
|
190
|
+
apiClient, conversationId, setMessages, setSendingIfCurrent, assistantCountBefore,
|
|
191
|
+
() => { setQueuedMessages([]); onConversationSettledRef.current?.(); },
|
|
192
|
+
() => onAgentMessageDoneRef.current?.(),
|
|
193
|
+
);
|
|
194
|
+
};
|
|
195
|
+
refreshConversation(apiClient, conversationId, setMessages)
|
|
196
|
+
.then((refreshed) => {
|
|
197
|
+
// agent_done arrived while a tool is still running in the snapshot —
|
|
198
|
+
// don't settle yet, let the poll loop finish it.
|
|
199
|
+
if (hasRunningToolCall(refreshed)) {
|
|
200
|
+
handOffToPoll(countAssistantResponses(refreshed));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
settle();
|
|
204
|
+
})
|
|
205
|
+
.catch(() => {
|
|
206
|
+
// The final refresh failed, so we can't tell whether a tool is still
|
|
207
|
+
// running — hand off to the bounded poll instead of clearing the busy
|
|
208
|
+
// state blind (it will settle on completion or the hard cap).
|
|
209
|
+
handOffToPoll(countAssistantResponses(messagesRef.current));
|
|
210
|
+
});
|
|
116
211
|
},
|
|
117
212
|
onReconnect() {
|
|
213
|
+
// A reconnect means the transient socket error cleared — drop the
|
|
214
|
+
// "something went wrong" state so it doesn't linger as a failed load.
|
|
215
|
+
setInitError(null);
|
|
118
216
|
if (apiClient) refreshConversation(apiClient, conversationId, setMessages).catch(() => {});
|
|
119
217
|
},
|
|
120
218
|
onError(error) {
|
|
121
219
|
setInitError(error instanceof Error ? error.message : 'Realtime connection failed');
|
|
122
220
|
},
|
|
123
221
|
});
|
|
124
|
-
}, [apiClient, conversationId,
|
|
222
|
+
}, [apiClient, conversationId, currentUserId, realtimeClient]);
|
|
125
223
|
|
|
126
224
|
const visibleMessages = useMemo(
|
|
127
225
|
() => messages.filter((message, index) => isVisibleMessage(message, index)),
|
|
128
226
|
[messages],
|
|
129
227
|
);
|
|
130
228
|
|
|
131
|
-
|
|
229
|
+
// Resolves true when the send was accepted (queued/sent), false when it failed
|
|
230
|
+
// before reaching the conversation — so the composer can restore the draft.
|
|
231
|
+
const sendMessage = useCallback(async (content: string, options: { fileUrls?: string[]; replyTo?: SuperagentReplyTo } = {}): Promise<boolean> => {
|
|
132
232
|
const trimmedContent = content.trim();
|
|
133
233
|
const fileUrls = options.fileUrls?.filter(Boolean) ?? [];
|
|
134
|
-
if (!trimmedContent && fileUrls.length === 0) return;
|
|
234
|
+
if (!trimmedContent && fileUrls.length === 0) return false;
|
|
235
|
+
|
|
236
|
+
// A new send supersedes any pending poll/settle timers from the previous one.
|
|
237
|
+
clearPendingSettlers();
|
|
135
238
|
|
|
136
|
-
const assistantCountBefore = countAssistantResponses(
|
|
239
|
+
const assistantCountBefore = countAssistantResponses(messagesRef.current);
|
|
137
240
|
const userMessage = createUserMessage(trimmedContent, { fileUrls, replyTo: options.replyTo });
|
|
138
241
|
setMessages((current) => [...current, userMessage]);
|
|
139
242
|
|
|
140
243
|
if (!apiClient || !conversationId) {
|
|
141
|
-
if (!onSendMessage)
|
|
244
|
+
if (!onSendMessage) {
|
|
245
|
+
// No send path yet (no fallback handler, or the conversation is still
|
|
246
|
+
// loading) — drop the optimistic bubble so the turn doesn't look sent.
|
|
247
|
+
setMessages((current) => current.filter((message) => message.id !== userMessage.id));
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
142
250
|
const sendGeneration = sendGenerationRef.current + 1;
|
|
143
251
|
sendGenerationRef.current = sendGeneration;
|
|
144
252
|
const setSendingForCurrentSend = (value: boolean) => {
|
|
@@ -146,9 +254,11 @@ export function useSuperagentConversation({
|
|
|
146
254
|
};
|
|
147
255
|
|
|
148
256
|
setIsSending(true);
|
|
149
|
-
const hasAssistantResponse = await sendWithFallback(agentId, trimmedContent, fileUrls, options.replyTo, onSendMessage, setMessages, setSendingForCurrentSend);
|
|
150
|
-
if (hasAssistantResponse)
|
|
151
|
-
|
|
257
|
+
const { delivered, hasAssistantResponse } = await sendWithFallback(agentId, trimmedContent, fileUrls, options.replyTo, onSendMessage, setMessages, setSendingForCurrentSend, userMessage.id);
|
|
258
|
+
if (hasAssistantResponse) onAgentMessageDoneRef.current?.();
|
|
259
|
+
// Report actual delivery so the composer restores the draft on a rejected
|
|
260
|
+
// fallback send instead of silently dropping the user's text/attachments.
|
|
261
|
+
return delivered;
|
|
152
262
|
}
|
|
153
263
|
|
|
154
264
|
const sendGeneration = sendGenerationRef.current + 1;
|
|
@@ -159,32 +269,105 @@ export function useSuperagentConversation({
|
|
|
159
269
|
|
|
160
270
|
setIsSending(true);
|
|
161
271
|
try {
|
|
272
|
+
// Wait for the turn to complete: poll without realtime, otherwise a 5s
|
|
273
|
+
// fallback in case agent_done never arrives.
|
|
274
|
+
const armSettleFallback = () => {
|
|
275
|
+
if (!realtimeClient) {
|
|
276
|
+
pollIntervalRef.current = pollConversation(
|
|
277
|
+
apiClient, conversationId, setMessages, setSendingForCurrentSend, assistantCountBefore,
|
|
278
|
+
() => { setQueuedMessages([]); onConversationSettledRef.current?.(); },
|
|
279
|
+
() => onAgentMessageDoneRef.current?.(),
|
|
280
|
+
);
|
|
281
|
+
} else {
|
|
282
|
+
settleTimeoutRef.current = setTimeout(async () => {
|
|
283
|
+
settleTimeoutRef.current = null;
|
|
284
|
+
// agent_done is late — hand off to the bounded poll loop, which keeps
|
|
285
|
+
// "sending" until tools finish (or the hard cap), instead of clearing
|
|
286
|
+
// it mid-turn.
|
|
287
|
+
const handOffToPoll = () => {
|
|
288
|
+
if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);
|
|
289
|
+
pollIntervalRef.current = pollConversation(
|
|
290
|
+
apiClient, conversationId, setMessages, setSendingForCurrentSend, assistantCountBefore,
|
|
291
|
+
() => { setQueuedMessages([]); onConversationSettledRef.current?.(); },
|
|
292
|
+
() => onAgentMessageDoneRef.current?.(),
|
|
293
|
+
);
|
|
294
|
+
};
|
|
295
|
+
try {
|
|
296
|
+
const refreshed = await refreshConversation(apiClient, conversationId, setMessages);
|
|
297
|
+
if (hasRunningToolCall(refreshed)) {
|
|
298
|
+
handOffToPoll();
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
} catch {
|
|
302
|
+
// Refresh failed — we can't tell whether a tool is still running, so
|
|
303
|
+
// hand off to the bounded poll rather than clearing the busy state
|
|
304
|
+
// blind (it retries and settles on completion or the hard cap).
|
|
305
|
+
handOffToPoll();
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
setSendingForCurrentSend(false);
|
|
309
|
+
setQueuedMessages([]);
|
|
310
|
+
onAgentMessageDoneRef.current?.();
|
|
311
|
+
onConversationSettledRef.current?.();
|
|
312
|
+
}, 5000);
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
|
|
162
316
|
const response = await apiClient.addMessage(conversationId, userMessage);
|
|
163
317
|
if (isQueuedResponse(response)) {
|
|
164
318
|
setQueuedMessages((current) => [...current, { id: userMessage.id!, content: userMessage.content, position: current.length }]);
|
|
319
|
+
// Another turn holds the conversation lock. Wait for OUR message to drain
|
|
320
|
+
// from the backend queue before settling — otherwise the running turn's
|
|
321
|
+
// completion would clear isSending / the queued strip early and let another
|
|
322
|
+
// send start while this one is still pending. pollQueuedSend re-baselines and
|
|
323
|
+
// hands off to the normal response poll once our turn actually starts.
|
|
324
|
+
if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);
|
|
325
|
+
pollIntervalRef.current = pollQueuedSend(
|
|
326
|
+
apiClient, conversationId, userMessage.id!, setMessages, setSendingForCurrentSend,
|
|
327
|
+
(interval) => { pollIntervalRef.current = interval; },
|
|
328
|
+
() => { setQueuedMessages([]); onConversationSettledRef.current?.(); },
|
|
329
|
+
() => onAgentMessageDoneRef.current?.(),
|
|
330
|
+
);
|
|
165
331
|
} else {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
332
|
+
let refreshedMessages;
|
|
333
|
+
try {
|
|
334
|
+
refreshedMessages = await refreshConversation(apiClient, conversationId, setMessages);
|
|
335
|
+
} catch {
|
|
336
|
+
// addMessage already succeeded (a non-queued send returns only after the
|
|
337
|
+
// agent is invoked), so the turn IS delivered. A failed post-send refresh
|
|
338
|
+
// must NOT drop the optimistic row or report failure — that would make
|
|
339
|
+
// ConversationChat restore the draft and the user resend, duplicating the
|
|
340
|
+
// message. Hand off to the bounded poll/settle loop and report delivered.
|
|
341
|
+
armSettleFallback();
|
|
342
|
+
return true;
|
|
343
|
+
}
|
|
344
|
+
// Only complete immediately if a new assistant reply landed AND no tool is
|
|
345
|
+
// still running — otherwise hand off to armSettleFallback (pollConversation
|
|
346
|
+
// without realtime), which keeps "sending" until tools finish. Matches the
|
|
347
|
+
// poll/settle paths so tool-using turns don't drop the busy state early.
|
|
348
|
+
if (!realtimeClient && hasNewAssistantResponse(refreshedMessages, assistantCountBefore) && !hasRunningToolCall(refreshedMessages)) {
|
|
349
|
+
setSendingForCurrentSend(false);
|
|
350
|
+
setQueuedMessages([]);
|
|
351
|
+
onAgentMessageDoneRef.current?.();
|
|
352
|
+
onConversationSettledRef.current?.();
|
|
175
353
|
} else {
|
|
176
|
-
|
|
177
|
-
setSendingForCurrentSend(false);
|
|
178
|
-
onConversationSettled?.();
|
|
179
|
-
}, 5000);
|
|
354
|
+
armSettleFallback();
|
|
180
355
|
}
|
|
181
356
|
}
|
|
357
|
+
return true;
|
|
182
358
|
} catch (error) {
|
|
359
|
+
// The optimistic bubble never reached the server (addMessage threw), so drop
|
|
360
|
+
// it and surface the error in its place — otherwise the turn looks sent and a
|
|
361
|
+
// later refresh/resend could duplicate it. Mirrors the no-send-path above.
|
|
183
362
|
const errorMessage = createErrorMessage(error);
|
|
184
|
-
setMessages((current) => [
|
|
363
|
+
setMessages((current) => [
|
|
364
|
+
...current.filter((message) => message.id !== userMessage.id),
|
|
365
|
+
errorMessage,
|
|
366
|
+
]);
|
|
185
367
|
setSendingForCurrentSend(false);
|
|
368
|
+
return false;
|
|
186
369
|
}
|
|
187
|
-
}, [agentId, apiClient,
|
|
370
|
+
}, [agentId, apiClient, clearPendingSettlers, conversationId, onSendMessage, realtimeClient]);
|
|
188
371
|
|
|
189
372
|
const deleteMessage = useCallback(async (messageId: string) => {
|
|
190
373
|
if (!messageId || messageId === 'welcome') return false;
|
|
@@ -196,16 +379,23 @@ export function useSuperagentConversation({
|
|
|
196
379
|
|
|
197
380
|
try {
|
|
198
381
|
await apiClient.deleteMessage(conversationId, messageId);
|
|
382
|
+
// Remove locally before refreshing: mergeConversationSnapshot keeps rows
|
|
383
|
+
// missing from the server snapshot, so without this the just-deleted
|
|
384
|
+
// message would be resurrected.
|
|
385
|
+
setMessages((current) => current.filter((message) => message.id !== messageId));
|
|
199
386
|
await refreshConversation(apiClient, conversationId, setMessages);
|
|
200
387
|
return true;
|
|
201
|
-
} catch
|
|
202
|
-
|
|
388
|
+
} catch {
|
|
389
|
+
// A failed delete is not a load failure — don't drive the "something went
|
|
390
|
+
// wrong" panel (it would persist). Signal failure via the return value so
|
|
391
|
+
// the caller can surface it.
|
|
203
392
|
return false;
|
|
204
393
|
}
|
|
205
394
|
}, [apiClient, conversationId]);
|
|
206
395
|
|
|
207
396
|
const stop = useCallback(async () => {
|
|
208
397
|
sendGenerationRef.current += 1;
|
|
398
|
+
clearPendingSettlers();
|
|
209
399
|
|
|
210
400
|
if (!apiClient || !conversationId) {
|
|
211
401
|
setIsSending(false);
|
|
@@ -216,20 +406,32 @@ export function useSuperagentConversation({
|
|
|
216
406
|
setQueuedMessages([]);
|
|
217
407
|
await apiClient.stopConversation(conversationId);
|
|
218
408
|
await refreshConversation(apiClient, conversationId, setMessages);
|
|
219
|
-
}, [apiClient, conversationId]);
|
|
409
|
+
}, [apiClient, clearPendingSettlers, conversationId]);
|
|
220
410
|
|
|
221
411
|
const loadPrevious = useCallback(async () => {
|
|
412
|
+
if (loadingPreviousRef.current) return;
|
|
222
413
|
const before = getMessageCursor(messages[0]);
|
|
223
414
|
if (!apiClient || !conversationId || !before) return;
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
415
|
+
loadingPreviousRef.current = true;
|
|
416
|
+
try {
|
|
417
|
+
const page = await apiClient.getMessages(conversationId, { limit: MESSAGES_PAGE_SIZE, before });
|
|
418
|
+
setMessages((current) => [...normalizeMessages(page.messages), ...current]);
|
|
419
|
+
setHasMoreMessages(Boolean(page.has_more ?? page.hasMore));
|
|
420
|
+
} catch {
|
|
421
|
+
// Pagination failed — swallow so it isn't an unhandled rejection from the
|
|
422
|
+
// button, and leave hasMoreMessages as-is so the user can retry.
|
|
423
|
+
} finally {
|
|
424
|
+
loadingPreviousRef.current = false;
|
|
425
|
+
}
|
|
227
426
|
}, [apiClient, conversationId, messages]);
|
|
228
427
|
|
|
229
428
|
const submitToolCallInput = useCallback(async (toolCallId: string, approve: boolean, extraUserInput?: unknown, originRequestId?: string): Promise<SuperagentConversation | null> => {
|
|
230
429
|
if (!apiClient || !conversationId) return null;
|
|
231
430
|
const updated = await apiClient.submitToolCallInput(conversationId, toolCallId, approve, extraUserInput, originRequestId);
|
|
232
|
-
if (updated.messages)
|
|
431
|
+
if (updated.messages) {
|
|
432
|
+
const incoming = normalizeMessages(updated.messages);
|
|
433
|
+
setMessages((current) => mergeConversationSnapshot(current, incoming));
|
|
434
|
+
}
|
|
233
435
|
onConversationSettled?.();
|
|
234
436
|
return updated;
|
|
235
437
|
}, [apiClient, conversationId, onConversationSettled]);
|