diff --git a/packages/app/src/components/agent-stream-view.tsx b/packages/app/src/components/agent-stream-view.tsx index 515a8154f..3f1013143 100644 --- a/packages/app/src/components/agent-stream-view.tsx +++ b/packages/app/src/components/agent-stream-view.tsx @@ -240,96 +240,99 @@ export function AgentStreamView({ setIsNearBottom(true); } - function renderStreamItem({ item }: ListRenderItemInfo) { - let content: React.ReactNode = null; + const renderStreamItem = useCallback( + ({ item }: ListRenderItemInfo) => { + let content: React.ReactNode = null; - switch (item.kind) { - case "user_message": - content = ( - - ); - break; - - case "assistant_message": - content = ( - - ); - break; - - case "thought": - content = ; - break; - - case "tool_call": { - const { payload } = item; - - if (payload.source === "agent") { - const data = payload.data; + switch (item.kind) { + case "user_message": content = ( - ); - } else { - const data = payload.data; + break; + + case "assistant_message": content = ( - ); + break; + + case "thought": + content = ; + break; + + case "tool_call": { + const { payload } = item; + + if (payload.source === "agent") { + const data = payload.data; + content = ( + + ); + } else { + const data = payload.data; + content = ( + + ); + } + break; } - break; + + case "activity_log": + content = ( + + ); + break; + + case "todo_list": + content = ( + + ); + break; + + default: + content = null; } - case "activity_log": - content = ( - - ); - break; + if (!content) { + return null; + } - case "todo_list": - content = ( - - ); - break; - - default: - content = null; - } - - if (!content) { - return null; - } - - return {content}; - } + return {content}; + }, + [handleInlinePathPress, agent.cwd] + ); const pendingPermissionItems = useMemo( () => @@ -339,30 +342,20 @@ export function AgentStreamView({ [pendingPermissions, agentId] ); - const streamingItem = useMemo(() => { - if (!streamingBuffer) { - return null; - } - return { - kind: "assistant_message", - id: streamingBuffer.id, - text: streamingBuffer.text, - timestamp: streamingBuffer.timestamp, - }; - }, [streamingBuffer]); - - const streamingItemId = streamingItem?.id ?? null; const showWorkingIndicator = agent.status === "running"; const listHeaderComponent = useMemo(() => { - if (pendingPermissionItems.length === 0 && !showWorkingIndicator) { + const hasPermissions = pendingPermissionItems.length > 0; + const hasStreaming = !!streamingBuffer; + + if (!hasPermissions && !showWorkingIndicator && !hasStreaming) { return null; } return ( - {pendingPermissionItems.length > 0 ? ( + {hasPermissions ? ( {pendingPermissionItems.map((permission) => ( @@ -375,18 +368,24 @@ export function AgentStreamView({ ) : null} + + {hasStreaming ? ( + + + + ) : null} ); - }, [pendingPermissionItems, showWorkingIndicator, wsOrInert]); + }, [pendingPermissionItems, showWorkingIndicator, wsOrInert, streamingBuffer, handleInlinePathPress]); const flatListData = useMemo(() => { - const reversed = [...streamItems].reverse(); - if (streamingItem) { - reversed.unshift(streamingItem); - } - return reversed; - }, [streamItems, streamingItem]); + return [...streamItems].reverse(); + }, [streamItems]); const flatListExtraData = useMemo( () => ({ diff --git a/packages/app/src/components/message.tsx b/packages/app/src/components/message.tsx index e96c099a3..52fb8a180 100644 --- a/packages/app/src/components/message.tsx +++ b/packages/app/src/components/message.tsx @@ -963,7 +963,7 @@ const agentThoughtStylesheet = StyleSheet.create((theme) => ({ }, })); -export function AgentThoughtMessage({ message, status = "ready" }: AgentThoughtMessageProps) { +export const AgentThoughtMessage = memo(function AgentThoughtMessage({ message, status = "ready" }: AgentThoughtMessageProps) { const { theme } = useUnistyles(); const [isExpanded, setIsExpanded] = useState(false); const markdownContent = useMemo(() => message?.trim() ?? "", [message]); @@ -1102,7 +1102,7 @@ export function AgentThoughtMessage({ message, status = "ready" }: AgentThoughtM isLoading={status !== "ready"} /> ); -} +}); interface ToolCallProps { toolName: string;