diff --git a/packages/ui/src/components/chat/StatusRowContainer.tsx b/packages/ui/src/components/chat/StatusRowContainer.tsx index 9c7da1f5..33872ac0 100644 --- a/packages/ui/src/components/chat/StatusRowContainer.tsx +++ b/packages/ui/src/components/chat/StatusRowContainer.tsx @@ -1,25 +1,71 @@ import React from 'react'; -import { useAssistantStatus } from '@/hooks/useAssistantStatus'; + +import { useCurrentSessionActivity } from '@/hooks/useSessionActivity'; import { useConfigStore } from '@/stores/useConfigStore'; +import { useSessionPermissions, useSessionStatus } from '@/sync/sync-context'; +import { useSessionUIStore } from '@/sync/session-ui-store'; import { StatusRow } from './StatusRow'; +const DEFAULT_WORKING_STATUS = 'working'; + /** - * Self-contained wrapper — subscribes to assistant status internally - * so MessageList doesn't re-render on every streaming part delta. + * Coarse status wrapper. + * Avoids subscribing to live assistant parts so the row doesn't rerender on every text delta. */ export const StatusRowContainer: React.FC = React.memo(() => { - const { working } = useAssistantStatus(); + const currentSessionId = useSessionUIStore((state) => state.currentSessionId); + const abortRecord = useSessionUIStore( + React.useCallback((state) => { + if (!currentSessionId) { + return null; + } + return state.sessionAbortFlags?.get(currentSessionId) ?? null; + }, [currentSessionId]), + ); + const permissions = useSessionPermissions(currentSessionId ?? ''); + const sessionStatus = useSessionStatus(currentSessionId ?? ''); + const { phase, isWorking } = useCurrentSessionActivity(); const currentAgentName = useConfigStore((state) => state.currentAgentName); + const wasAborted = Boolean(abortRecord && !abortRecord.acknowledged); + const isWaitingForPermission = permissions.length > 0; + const isRetry = sessionStatus?.type === 'retry'; + + const statusText = React.useMemo(() => { + if (isWaitingForPermission) { + return 'waiting for permission'; + } + if (isRetry) { + return 'retrying'; + } + if (!isWorking) { + return null; + } + if (phase === 'busy') { + return 'composing'; + } + return DEFAULT_WORKING_STATUS; + }, [isRetry, isWaitingForPermission, isWorking, phase]); + + const retryInfo = React.useMemo(() => { + if (!isRetry) { + return null; + } + return { + attempt: (sessionStatus as { attempt?: number } | undefined)?.attempt, + next: (sessionStatus as { next?: number } | undefined)?.next, + }; + }, [isRetry, sessionStatus]); + return (