import { useT } from "@agent-native/core/client/i18n";
import {
HeaderActionsProvider,
useHeaderActions,
useHeaderTitle,
} from "@agent-native/toolkit/app-shell/header-actions";
import {
isAgentChatHomeHandoffActive,
useAgentChatHomeHandoff,
useAgentChatHomeHandoffLinks,
} from "@agent-native/toolkit/app/chat/agentkit-chat/rail";
import {
RealtimeVoiceModeProvider,
useRealtimeVoiceModeOptional,
} from "@agent-native/toolkit/app/chat/composer";
import { isSettingsPathname } from "@agent-native/toolkit/app/settings";
import { lazy, Suspense, useEffect, useRef, useState } from "react";
import { useLocation } from "react-router";
import {
Sheet,
SheetContent,
SheetDescription,
SheetTitle,
} from "@/components/ui/sheet";
import { APP_TITLE } from "@/lib/app-config";
import { HOME_PATH, isChatPathname } from "@/lib/chat-paths";
import { TAB_ID } from "@/lib/tab-id";
// Not lazy() like Header: the inspector wraps the page, so a Suspense fallback
// would mount the page once before its chunk loads and again after.
// AgentSidebar already lazy-loads its own panel.
import { AgentInspector } from "./AgentInspector";
import { MobileAppBar } from "./MobileAppBar";
import { Sidebar } from "./Sidebar";
const Header = lazy(() =>
import("./Header").then((module) => ({ default: module.Header })),
);
interface LayoutProps {
children: React.ReactNode;
}
const SIDEBAR_COLLAPSE_KEY = "chat.sidebar.collapsed";
function routeOwnsToolbar(pathname: string): boolean {
return (
pathname === HOME_PATH ||
isChatPathname(pathname) ||
pathname === "/database" ||
pathname.startsWith("/extensions")
);
}
/**
* A voice chat follows the user into a chat thread, so Get started can hand
* one off. Other pages show no controls for this session, so any other
* navigation ends it rather than leave the microphone open with nothing to
* stop it. The agent sidebar owns a separate session and keeps its own
* controls on screen, so this leaves that one alone.
*/
function EndVoiceChatOutsideChat() {
const { pathname } = useLocation();
const end = useRealtimeVoiceModeOptional()?.end;
const previousPathnameRef = useRef(pathname);
useEffect(() => {
if (previousPathnameRef.current === pathname) return;
previousPathnameRef.current = pathname;
if (!isChatPathname(pathname)) end?.();
}, [end, pathname]);
return null;
}
export function Layout({ children }: LayoutProps) {
return (