diff --git a/packages/app/src/app/agent/[id].tsx b/packages/app/src/app/agent/[id].tsx index 90d105e78..3fe5d7f5e 100644 --- a/packages/app/src/app/agent/[id].tsx +++ b/packages/app/src/app/agent/[id].tsx @@ -96,6 +96,7 @@ export default function AgentScreen() { onPermissionResponse={(requestId, optionId) => respondToPermission(requestId, id!, agent.sessionId || "", [optionId]) } + keyboardHeight={keyboardHeight} /> )} diff --git a/packages/app/src/components/agent-stream-view.tsx b/packages/app/src/components/agent-stream-view.tsx index 552bb7fbe..49466e1bf 100644 --- a/packages/app/src/components/agent-stream-view.tsx +++ b/packages/app/src/components/agent-stream-view.tsx @@ -3,7 +3,7 @@ import { View, Text, ScrollView, Pressable } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { StyleSheet, useUnistyles } from "react-native-unistyles"; import { BottomSheetModal } from "@gorhom/bottom-sheet"; -import Animated, { FadeIn, FadeOut } from "react-native-reanimated"; +import Animated, { FadeIn, FadeOut, useAnimatedStyle, SharedValue } from "react-native-reanimated"; import { ChevronDown } from "lucide-react-native"; import { AssistantMessage, @@ -25,6 +25,7 @@ export interface AgentStreamViewProps { streamItems: StreamItem[]; pendingPermissions: Map; onPermissionResponse: (requestId: string, optionId: string) => void; + keyboardHeight: SharedValue; } export function AgentStreamView({ @@ -33,6 +34,7 @@ export function AgentStreamView({ streamItems, pendingPermissions, onPermissionResponse, + keyboardHeight, }: AgentStreamViewProps) { const scrollViewRef = useRef(null); const bottomSheetRef = useRef(null); @@ -42,6 +44,17 @@ export function AgentStreamView({ const [isNearBottom, setIsNearBottom] = useState(true); const hasScrolledInitially = useRef(false); + // Animated content padding that responds to keyboard + const contentPaddingStyle = useAnimatedStyle(() => { + "worklet"; + const absoluteHeight = Math.abs(keyboardHeight.value); + const keyboardPadding = Math.max(0, absoluteHeight - insets.bottom); + const basePadding = Math.max(insets.bottom, 32); + return { + paddingBottom: basePadding + keyboardPadding, + }; + }, [insets.bottom]); + // Scroll to bottom immediately on initial load, then animate for new messages useEffect(() => { if (isNearBottom) { @@ -82,10 +95,12 @@ export function AgentStreamView({