feat: add relay reconnect with grace period and branch suggestions
This commit is contained in:
@@ -276,13 +276,11 @@ export function AgentInputArea({
|
||||
imageAttachments?: ImageAttachment[],
|
||||
forceSend?: boolean
|
||||
) {
|
||||
const socketConnected = isConnected;
|
||||
const trimmedMessage = message.trim();
|
||||
if (!trimmedMessage) return;
|
||||
// When the parent controls submission (e.g. draft agent creation), let it
|
||||
// decide what to do even if the socket is currently disconnected (so we
|
||||
// don't no-op and lose deterministic error handling in the UI/tests).
|
||||
if (!onSubmitMessageRef.current && !socketConnected) return;
|
||||
if (!sendAgentMessageRef.current && !onSubmitMessageRef.current) return;
|
||||
|
||||
if (agent?.status === "running" && !forceSend) {
|
||||
@@ -485,7 +483,7 @@ export function AgentInputArea({
|
||||
|
||||
async function handleSendQueuedNow(id: string) {
|
||||
const item = queuedMessages.find((q) => q.id === id);
|
||||
if (!item || !isConnected) return;
|
||||
if (!item) return;
|
||||
if (!sendAgentMessageRef.current && !onSubmitMessageRef.current) return;
|
||||
|
||||
updateQueue((current) => current.filter((q) => q.id !== id));
|
||||
|
||||
@@ -731,7 +731,7 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(
|
||||
scrollEnabled={IS_WEB ? inputHeight >= MAX_INPUT_HEIGHT : true}
|
||||
onContentSizeChange={handleContentSizeChange}
|
||||
editable={
|
||||
!isDictating && !isRealtimeVoiceForCurrentAgent && isConnected && !disabled
|
||||
!isDictating && !isRealtimeVoiceForCurrentAgent && !disabled
|
||||
}
|
||||
onKeyPress={
|
||||
shouldHandleDesktopSubmit ? handleDesktopKeyPress : undefined
|
||||
@@ -836,24 +836,22 @@ export const MessageInput = forwardRef<MessageInputRef, MessageInputProps>(
|
||||
)}
|
||||
{shouldShowSendButton && (
|
||||
<Tooltip delayDuration={0} enabledOnDesktop enabledOnMobile={false}>
|
||||
<TooltipTrigger
|
||||
onPress={handleSendMessage}
|
||||
disabled={
|
||||
!isConnected ||
|
||||
<TooltipTrigger
|
||||
onPress={handleSendMessage}
|
||||
disabled={
|
||||
isSubmitDisabled ||
|
||||
isSubmitLoading ||
|
||||
disabled
|
||||
}
|
||||
accessibilityLabel={isAgentRunning ? "Send and interrupt" : "Send message"}
|
||||
accessibilityRole="button"
|
||||
style={[
|
||||
styles.sendButton,
|
||||
(!isConnected ||
|
||||
isSubmitDisabled ||
|
||||
accessibilityLabel={isAgentRunning ? "Send and interrupt" : "Send message"}
|
||||
accessibilityRole="button"
|
||||
style={[
|
||||
styles.sendButton,
|
||||
(isSubmitDisabled ||
|
||||
isSubmitLoading ||
|
||||
disabled) &&
|
||||
styles.buttonDisabled,
|
||||
]}
|
||||
]}
|
||||
>
|
||||
{isSubmitLoading ? (
|
||||
<ActivityIndicator size="small" color="white" />
|
||||
|
||||
@@ -183,7 +183,7 @@ function ManagedDaemonSession({ daemon }: { daemon: HostProfile }) {
|
||||
|
||||
return (
|
||||
<SessionProvider
|
||||
key={`${daemon.serverId}:${activeUrl}`}
|
||||
key={daemon.serverId}
|
||||
serverUrl={activeUrl}
|
||||
serverId={daemon.serverId}
|
||||
activeConnection={active?.activeConnection ?? null}
|
||||
|
||||
@@ -35,6 +35,7 @@ export interface ComboboxProps {
|
||||
options: ComboboxOption[];
|
||||
value: string;
|
||||
onSelect: (id: string) => void;
|
||||
onSearchQueryChange?: (query: string) => void;
|
||||
placeholder?: string;
|
||||
searchPlaceholder?: string;
|
||||
emptyText?: string;
|
||||
@@ -156,6 +157,7 @@ export function Combobox({
|
||||
options,
|
||||
value,
|
||||
onSelect,
|
||||
onSearchQueryChange,
|
||||
placeholder = "Search...",
|
||||
searchPlaceholder,
|
||||
emptyText = "No options match your search.",
|
||||
@@ -191,16 +193,24 @@ export function Combobox({
|
||||
[isControlled, onOpenChange]
|
||||
);
|
||||
|
||||
const setSearchQueryWithCallback = useCallback(
|
||||
(nextQuery: string) => {
|
||||
setSearchQuery(nextQuery);
|
||||
onSearchQueryChange?.(nextQuery);
|
||||
},
|
||||
[onSearchQueryChange]
|
||||
);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
setOpen(false);
|
||||
setSearchQuery("");
|
||||
}, [setOpen]);
|
||||
setSearchQueryWithCallback("");
|
||||
}, [setOpen, setSearchQueryWithCallback]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
setSearchQuery("");
|
||||
setSearchQueryWithCallback("");
|
||||
}
|
||||
}, [isOpen]);
|
||||
}, [isOpen, setSearchQueryWithCallback]);
|
||||
|
||||
const collisionPadding = useMemo(() => {
|
||||
const basePadding = 16;
|
||||
@@ -426,7 +436,7 @@ export function Combobox({
|
||||
<SearchInput
|
||||
placeholder={searchPlaceholder ?? placeholder}
|
||||
value={searchQuery}
|
||||
onChangeText={setSearchQuery}
|
||||
onChangeText={setSearchQueryWithCallback}
|
||||
onSubmitEditing={handleSubmitSearch}
|
||||
autoFocus={!isMobile}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user