diff --git a/desktop/src/features/chats/ui/ChatConversationRows.tsx b/desktop/src/features/chats/ui/ChatConversationRows.tsx index 63335f711..3bae8289b 100644 --- a/desktop/src/features/chats/ui/ChatConversationRows.tsx +++ b/desktop/src/features/chats/ui/ChatConversationRows.tsx @@ -232,11 +232,14 @@ export function AgentActivationCard({

- Activate {agentName} to get a response + {isActivating + ? `Starting ${agentName}…` + : `Activate ${agentName} to get a response`}

- Your message was sent, but this agent is not active in this - chat yet. + {isActivating + ? "It will pick up your message as soon as it connects." + : "Your message was sent, but this agent is not active in this chat yet."}

diff --git a/desktop/src/features/chats/ui/ChatDetail.tsx b/desktop/src/features/chats/ui/ChatDetail.tsx index 0fcf8c4f5..d1c8c7589 100644 --- a/desktop/src/features/chats/ui/ChatDetail.tsx +++ b/desktop/src/features/chats/ui/ChatDetail.tsx @@ -470,6 +470,30 @@ export function ChatDetail({ // message, and start its turn. Without this grace window the card re-shows // ~1s after activation and reads as "activation didn't work". const AGENT_ACTIVATION_GRACE_MS = 20_000; + // "Activated" isn't done until the agent responds: the card's button holds + // its loading state from click until this chat has a live turn (the card + // unmounts then) or the give-up window expires — the start API returning + // only means the process launched, not that it's connected and replaying + // the pending message. + const ACTIVATION_PENDING_MS = 60_000; + const [isActivationPending, setIsActivationPending] = React.useState(false); + const handleActivateAgent = React.useCallback(() => { + setIsActivationPending(true); + onActivateAgent(); + }, [onActivateAgent]); + React.useEffect(() => { + if (!isActivationPending) { + return; + } + if (isChatTurnActive) { + setIsActivationPending(false); + return; + } + const timeout = window.setTimeout(() => { + setIsActivationPending(false); + }, ACTIVATION_PENDING_MS); + return () => window.clearTimeout(timeout); + }, [isActivationPending, isChatTurnActive]); const [activationGraceUntil, setActivationGraceUntil] = React.useState(0); const wasActivatingRef = React.useRef(false); React.useEffect(() => { @@ -620,8 +644,10 @@ export function ChatDetail({ > ) : null} diff --git a/desktop/src/features/chats/ui/ChatsScreen.tsx b/desktop/src/features/chats/ui/ChatsScreen.tsx index 855cefdcd..b2af641d5 100644 --- a/desktop/src/features/chats/ui/ChatsScreen.tsx +++ b/desktop/src/features/chats/ui/ChatsScreen.tsx @@ -516,10 +516,10 @@ export function ChatsScreen({ defaultAgent.status !== "running" && defaultAgent.status !== "deployed" ) { - const updatedAgent = await startManagedAgentMutation.mutateAsync( - defaultAgent.pubkey, - ); - toast.success(`${updatedAgent.name || defaultAgent.name} activated`); + // No success toast: the process starting is not the same as the + // agent responding — the activation card holds its loading state + // until the agent's turn actually begins. + await startManagedAgentMutation.mutateAsync(defaultAgent.pubkey); } else { await managedAgentsQuery.refetch(); toast.success(`${defaultAgent.name} activated`);