2026-03-31 18:47:00 +03:00
|
|
|
import React from 'react';
|
2026-04-05 17:29:14 +03:00
|
|
|
|
|
|
|
|
import { useCurrentSessionActivity } from '@/hooks/useSessionActivity';
|
2026-03-31 18:47:00 +03:00
|
|
|
import { useConfigStore } from '@/stores/useConfigStore';
|
2026-04-05 17:29:14 +03:00
|
|
|
import { useSessionPermissions, useSessionStatus } from '@/sync/sync-context';
|
|
|
|
|
import { useSessionUIStore } from '@/sync/session-ui-store';
|
2026-03-31 18:47:00 +03:00
|
|
|
import { StatusRow } from './StatusRow';
|
|
|
|
|
|
2026-04-05 17:29:14 +03:00
|
|
|
const DEFAULT_WORKING_STATUS = 'working';
|
|
|
|
|
|
2026-03-31 18:47:00 +03:00
|
|
|
/**
|
2026-04-05 17:29:14 +03:00
|
|
|
* Coarse status wrapper.
|
|
|
|
|
* Avoids subscribing to live assistant parts so the row doesn't rerender on every text delta.
|
2026-03-31 18:47:00 +03:00
|
|
|
*/
|
|
|
|
|
export const StatusRowContainer: React.FC = React.memo(() => {
|
2026-04-05 17:29:14 +03:00
|
|
|
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();
|
2026-03-31 18:47:00 +03:00
|
|
|
const currentAgentName = useConfigStore((state) => state.currentAgentName);
|
|
|
|
|
|
2026-04-05 17:29:14 +03:00
|
|
|
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]);
|
|
|
|
|
|
2026-03-31 18:47:00 +03:00
|
|
|
return (
|
|
|
|
|
<StatusRow
|
2026-04-05 17:29:14 +03:00
|
|
|
isWorking={isWorking}
|
|
|
|
|
statusText={statusText}
|
|
|
|
|
isGenericStatus={true}
|
|
|
|
|
isWaitingForPermission={isWaitingForPermission}
|
|
|
|
|
wasAborted={wasAborted}
|
|
|
|
|
abortActive={wasAborted}
|
|
|
|
|
retryInfo={retryInfo}
|
2026-03-31 18:47:00 +03:00
|
|
|
showAssistantStatus
|
|
|
|
|
showTodos={false}
|
|
|
|
|
agentName={currentAgentName}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
StatusRowContainer.displayName = 'StatusRowContainer';
|