diff --git a/src/components/cloud-agent-next/CloudChatContainer.tsx b/src/components/cloud-agent-next/CloudChatContainer.tsx index 743da2028..914e0030d 100644 --- a/src/components/cloud-agent-next/CloudChatContainer.tsx +++ b/src/components/cloud-agent-next/CloudChatContainer.tsx @@ -47,7 +47,6 @@ import { useCloudAgentStream } from './useCloudAgentStream'; import { useAutoScroll } from './hooks/useAutoScroll'; import { useCelebrationSound } from '@/hooks/useCelebrationSound'; import { useNotificationSound } from '@/hooks/useNotificationSound'; -import { useSidebarSessions } from './hooks/useSidebarSessions'; import { useOrganizationModels } from './hooks/useOrganizationModels'; import { useSessionDeletion } from './hooks/useSessionDeletion'; import { useResumeConfigModal } from './hooks/useResumeConfigModal'; @@ -59,7 +58,7 @@ import { useSlashCommandSets } from '@/hooks/useSlashCommandSets'; import { CloudChatPresentation } from './CloudChatPresentation'; import { QuestionContextProvider } from './QuestionContext'; import type { ResumeConfig } from './ResumeConfigModal'; -import type { AgentMode, SessionStartConfig } from './types'; +import type { AgentMode, SessionStartConfig, StoredSession } from './types'; /** Normalize legacy mode strings ('build' → 'code', 'architect' → 'plan') from DB/DO */ function normalizeMode(mode: string): AgentMode { @@ -70,9 +69,15 @@ function normalizeMode(mode: string): AgentMode { type CloudChatContainerProps = { organizationId?: string; + sessions: StoredSession[]; + refetchSessions: () => void; }; -export function CloudChatContainer({ organizationId }: CloudChatContainerProps) { +export function CloudChatContainer({ + organizationId, + sessions, + refetchSessions, +}: CloudChatContainerProps) { const router = useRouter(); const searchParams = useSearchParams(); const trpc = useTRPC(); @@ -267,12 +272,6 @@ export function CloudChatContainer({ organizationId }: CloudChatContainerProps) setIsSessionInitiated(true); }, []); - // Sidebar sessions (scoped to organization when in org context, personal-only when undefined) - // Pass null for personal chat to filter out org sessions, or the org ID for org chat - const { sessions, refetchSessions } = useSidebarSessions({ - organizationId: organizationId ?? null, - }); - // Callback for stream completion const handleStreamComplete = useCallback(() => { playCelebrationSound(); diff --git a/src/components/cloud-agent-next/CloudChatPage.tsx b/src/components/cloud-agent-next/CloudChatPage.tsx index c73281291..46f465e58 100644 --- a/src/components/cloud-agent-next/CloudChatPage.tsx +++ b/src/components/cloud-agent-next/CloudChatPage.tsx @@ -1,24 +1,31 @@ /** * Cloud Chat Page * - * Simple wrapper that exports the CloudChatContainer component. - * All business logic, hooks, and state management are in CloudChatContainer. - * All rendering logic is in CloudChatPresentation. + * Owns the sidebar session query so it runs outside CloudChatContainer, + * whose frequent internal state changes would otherwise cause redundant + * unifiedSessions.list invocations batched by tRPC. */ 'use client'; import { CloudChatContainer } from './CloudChatContainer'; +import { useSidebarSessions } from './hooks/useSidebarSessions'; type CloudChatPageProps = { organizationId?: string; }; -/** - * Main export - renders the cloud chat container - */ -export default function CloudChatPage(props: CloudChatPageProps) { - return ; +export default function CloudChatPage({ organizationId }: CloudChatPageProps) { + const { sessions, refetchSessions } = useSidebarSessions({ + organizationId: organizationId ?? null, + }); + return ( + + ); } // Named export for compatibility diff --git a/src/components/cloud-agent/CloudChatContainer.tsx b/src/components/cloud-agent/CloudChatContainer.tsx index 47c2a862f..6ffd5987a 100644 --- a/src/components/cloud-agent/CloudChatContainer.tsx +++ b/src/components/cloud-agent/CloudChatContainer.tsx @@ -40,7 +40,6 @@ import { import { useCloudAgentStreamV2 } from './useCloudAgentStreamV2'; import { useAutoScroll } from './hooks/useAutoScroll'; import { useCelebrationSound } from '@/hooks/useCelebrationSound'; -import { useSidebarSessions } from './hooks/useSidebarSessions'; import { useOrganizationModels } from './hooks/useOrganizationModels'; import { useSessionDeletion } from './hooks/useSessionDeletion'; import { useResumeConfigModal } from './hooks/useResumeConfigModal'; @@ -51,10 +50,12 @@ import { buildPrepareSessionRepoParams } from './utils/git-utils'; import { useSlashCommandSets } from '@/hooks/useSlashCommandSets'; import { CloudChatPresentation } from './CloudChatPresentation'; import type { ResumeConfig } from './ResumeConfigModal'; -import type { AgentMode, SessionStartConfig } from './types'; +import type { AgentMode, SessionStartConfig, StoredSession } from './types'; type CloudChatContainerProps = { organizationId?: string; + sessions: StoredSession[]; + refetchSessions: () => void; }; /** @@ -85,7 +86,11 @@ type ResumeConfigState = | { status: 'persisted'; config: ResumeConfig } | { status: 'failed'; config: ResumeConfig; error: Error }; -export function CloudChatContainer({ organizationId }: CloudChatContainerProps) { +export function CloudChatContainer({ + organizationId, + sessions, + refetchSessions, +}: CloudChatContainerProps) { const router = useRouter(); const searchParams = useSearchParams(); const trpc = useTRPC(); @@ -234,12 +239,6 @@ export function CloudChatContainer({ organizationId }: CloudChatContainerProps) setIsSessionInitiated(true); }, []); - // Sidebar sessions (scoped to organization when in org context, personal-only when undefined) - // Pass null for personal chat to filter out org sessions, or the org ID for org chat - const { sessions, refetchSessions } = useSidebarSessions({ - organizationId: organizationId ?? null, - }); - // Callback for stream completion const handleStreamComplete = useCallback(() => { playCelebrationSound(); diff --git a/src/components/cloud-agent/CloudChatPage.tsx b/src/components/cloud-agent/CloudChatPage.tsx index c73281291..46f465e58 100644 --- a/src/components/cloud-agent/CloudChatPage.tsx +++ b/src/components/cloud-agent/CloudChatPage.tsx @@ -1,24 +1,31 @@ /** * Cloud Chat Page * - * Simple wrapper that exports the CloudChatContainer component. - * All business logic, hooks, and state management are in CloudChatContainer. - * All rendering logic is in CloudChatPresentation. + * Owns the sidebar session query so it runs outside CloudChatContainer, + * whose frequent internal state changes would otherwise cause redundant + * unifiedSessions.list invocations batched by tRPC. */ 'use client'; import { CloudChatContainer } from './CloudChatContainer'; +import { useSidebarSessions } from './hooks/useSidebarSessions'; type CloudChatPageProps = { organizationId?: string; }; -/** - * Main export - renders the cloud chat container - */ -export default function CloudChatPage(props: CloudChatPageProps) { - return ; +export default function CloudChatPage({ organizationId }: CloudChatPageProps) { + const { sessions, refetchSessions } = useSidebarSessions({ + organizationId: organizationId ?? null, + }); + return ( + + ); } // Named export for compatibility