Initial commit from agent-native create
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
import {
|
||||
AgentChatSurface,
|
||||
markAgentChatHomeHandoff,
|
||||
} from "@agent-native/core/client/agent-chat";
|
||||
import { useT } from "@agent-native/core/client/i18n";
|
||||
import { useEffect } from "react";
|
||||
import { useNavigate, useParams } from "react-router";
|
||||
|
||||
import { APP_TITLE } from "@/lib/app-config";
|
||||
import { TAB_ID } from "@/lib/tab-id";
|
||||
|
||||
const SEO_TITLE = `${APP_TITLE} - Open Source AI app starter with actions`;
|
||||
const SEO_DESCRIPTION =
|
||||
"Open Source starter for agent-native apps with durable chat, shared actions, UI state, tools, and a backend your agent can extend.";
|
||||
|
||||
export function meta() {
|
||||
return [
|
||||
{ title: SEO_TITLE },
|
||||
{
|
||||
name: "description",
|
||||
content: SEO_DESCRIPTION,
|
||||
},
|
||||
{ property: "og:title", content: SEO_TITLE },
|
||||
{ property: "og:description", content: SEO_DESCRIPTION },
|
||||
{ name: "twitter:card", content: "summary" },
|
||||
{ name: "twitter:title", content: SEO_TITLE },
|
||||
{ name: "twitter:description", content: SEO_DESCRIPTION },
|
||||
];
|
||||
}
|
||||
|
||||
function chatThreadPath(threadId: string | null) {
|
||||
return threadId ? `/chat/${encodeURIComponent(threadId)}` : "/";
|
||||
}
|
||||
|
||||
export default function ChatRoute() {
|
||||
const { threadId } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const t = useT();
|
||||
const threadUrlSync = threadId
|
||||
? {
|
||||
routeThreadId: threadId,
|
||||
getPath: chatThreadPath,
|
||||
navigate,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
useEffect(() => {
|
||||
function handleChatRunning(event: Event) {
|
||||
const detail = (event as CustomEvent).detail;
|
||||
if (detail?.isRunning === true) markAgentChatHomeHandoff("chat");
|
||||
}
|
||||
|
||||
window.addEventListener("agentNative.chatRunning", handleChatRunning);
|
||||
return () =>
|
||||
window.removeEventListener("agentNative.chatRunning", handleChatRunning);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="flex h-full min-h-0 flex-col bg-background">
|
||||
<AgentChatSurface
|
||||
mode="page"
|
||||
chatViewTransition
|
||||
className="h-full"
|
||||
defaultMode="chat"
|
||||
storageKey="chat"
|
||||
threadUrlSync={threadUrlSync}
|
||||
browserTabId={TAB_ID}
|
||||
showHeader={false}
|
||||
showTabBar={false}
|
||||
dynamicSuggestions={false}
|
||||
suggestions={[
|
||||
t("chat.suggestionCapabilities"),
|
||||
t("chat.suggestionCustomize"),
|
||||
t("chat.suggestionActions"),
|
||||
]}
|
||||
emptyStateText={t("chat.emptyState")}
|
||||
emptyStateDisplay="hidden"
|
||||
centerComposerWhenEmpty
|
||||
composerLayoutVariant="hero"
|
||||
composerPlaceholder={t("chat.composerPlaceholder")}
|
||||
composerSlot={
|
||||
<div className="mx-auto mb-5 max-w-xl px-4 text-center">
|
||||
<h1 className="text-2xl font-semibold tracking-normal text-foreground sm:text-3xl">
|
||||
{t("chat.heroTitle")}
|
||||
</h1>
|
||||
<p className="mt-2 text-sm leading-6 text-muted-foreground">
|
||||
{t("chat.heroDescription")}
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
import {
|
||||
AgentChatSurface,
|
||||
AgentTabsPage,
|
||||
} from "@agent-native/core/client/agent-chat";
|
||||
import { useT } from "@agent-native/core/client/i18n";
|
||||
import { useSetPageTitle } from "@agent-native/toolkit/app-shell";
|
||||
|
||||
import { resolveAgentPageComponent } from "@/lib/agent-page";
|
||||
import { APP_TITLE } from "@/lib/app-config";
|
||||
|
||||
export function meta() {
|
||||
return [{ title: `Agent - ${APP_TITLE}` }];
|
||||
}
|
||||
|
||||
export default function AgentRoute() {
|
||||
const t = useT();
|
||||
useSetPageTitle(t("settings.agentTitle"));
|
||||
|
||||
const AgentPage = resolveAgentPageComponent({
|
||||
AgentChatSurface,
|
||||
AgentTabsPage,
|
||||
});
|
||||
return <AgentPage appName={APP_TITLE} />;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export { default, meta } from "./_index";
|
||||
@@ -0,0 +1,17 @@
|
||||
import { DbAdminPage } from "@agent-native/core/client/db-admin";
|
||||
import { useT } from "@agent-native/core/client/i18n";
|
||||
import { useSetPageTitle } from "@agent-native/toolkit/app-shell";
|
||||
|
||||
export function meta() {
|
||||
return [{ title: "Database" }];
|
||||
}
|
||||
|
||||
export default function DatabasePage() {
|
||||
const t = useT();
|
||||
useSetPageTitle(t("pages.databaseTitle"));
|
||||
return (
|
||||
<div className="h-full">
|
||||
<DbAdminPage />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./extensions.$id";
|
||||
export { default } from "./extensions.$id";
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ExtensionViewerPage } from "@agent-native/core/client/extensions";
|
||||
|
||||
import { APP_TITLE } from "@/lib/app-config";
|
||||
|
||||
export function meta() {
|
||||
return [{ title: `Extension — ${APP_TITLE}` }];
|
||||
}
|
||||
|
||||
export default function ExtensionViewerRoute() {
|
||||
return <ExtensionViewerPage />;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Navigate } from "react-router";
|
||||
|
||||
import { APP_TITLE } from "@/lib/app-config";
|
||||
|
||||
export function meta() {
|
||||
return [{ title: `Extensions — ${APP_TITLE}` }];
|
||||
}
|
||||
|
||||
export default function ExtensionsRoute() {
|
||||
return <Navigate to="/settings#extensions" replace />;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { Outlet } from "react-router";
|
||||
|
||||
export default function ExtensionsLayout() {
|
||||
return <Outlet />;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { useT } from "@agent-native/core/client/i18n";
|
||||
import { ObservabilityDashboard } from "@agent-native/core/client/observability";
|
||||
import { useSetPageTitle } from "@agent-native/toolkit/app-shell";
|
||||
|
||||
import enUS from "@/i18n/en-US";
|
||||
|
||||
export function meta() {
|
||||
return [{ title: enUS.pages.observabilityPageTitle }];
|
||||
}
|
||||
|
||||
export default function ObservabilityPage() {
|
||||
const t = useT();
|
||||
useSetPageTitle(t("pages.observabilityPageTitle"));
|
||||
return (
|
||||
<div className="p-6">
|
||||
<ObservabilityDashboard />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
import { ChangelogSettingsCard } from "@agent-native/core/client/changelog";
|
||||
import { LanguagePicker, useT } from "@agent-native/core/client/i18n";
|
||||
import { TeamPage } from "@agent-native/core/client/org";
|
||||
import {
|
||||
AccountSettingsCard,
|
||||
SettingsTabsPage,
|
||||
useAgentSettingsTabs,
|
||||
type SettingsSearchEntry,
|
||||
} from "@agent-native/core/client/settings";
|
||||
import { useSetPageTitle } from "@agent-native/toolkit/app-shell";
|
||||
import { useMemo } from "react";
|
||||
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { APP_TITLE } from "@/lib/app-config";
|
||||
|
||||
import changelog from "../../CHANGELOG.md?raw";
|
||||
|
||||
export function meta() {
|
||||
return [{ title: `Settings - ${APP_TITLE}` }];
|
||||
}
|
||||
|
||||
export default function SettingsRoute() {
|
||||
const t = useT();
|
||||
const agentSettingsTabs = useAgentSettingsTabs();
|
||||
useSetPageTitle(t("settings.title"));
|
||||
|
||||
const generalSearchEntries = useMemo<SettingsSearchEntry[]>(
|
||||
() => [
|
||||
{
|
||||
id: "chat-language",
|
||||
label: t("settings.languageTitle"),
|
||||
keywords: "language locale translation i18n",
|
||||
hash: "language",
|
||||
},
|
||||
],
|
||||
[t],
|
||||
);
|
||||
|
||||
return (
|
||||
<SettingsTabsPage
|
||||
account={<AccountSettingsCard />}
|
||||
teamLabel={t("navigation.team")}
|
||||
extraTabs={agentSettingsTabs}
|
||||
generalSearchEntries={generalSearchEntries}
|
||||
general={
|
||||
<div className="mx-auto w-full max-w-2xl space-y-6">
|
||||
<p className="text-sm leading-6 text-muted-foreground">
|
||||
{t("settings.description")}
|
||||
</p>
|
||||
|
||||
<Card id="language" className="scroll-mt-16">
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">
|
||||
{t("settings.languageTitle")}
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
{t("settings.languageDescription")}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="max-w-xs space-y-1.5">
|
||||
<Label>{t("settings.languageLabel")}</Label>
|
||||
<LanguagePicker label={t("settings.languageLabel")} />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</div>
|
||||
}
|
||||
team={
|
||||
<div className="mx-auto w-full max-w-3xl">
|
||||
<TeamPage
|
||||
showTitle={false}
|
||||
createOrgDescription={t("pages.teamCreateOrgDescription")}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
whatsNew={
|
||||
<div className="mx-auto w-full max-w-2xl">
|
||||
<ChangelogSettingsCard markdown={changelog} />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Navigate } from "react-router";
|
||||
|
||||
import { APP_TITLE } from "@/lib/app-config";
|
||||
|
||||
export function meta() {
|
||||
return [{ title: `Team — ${APP_TITLE}` }];
|
||||
}
|
||||
|
||||
export default function TeamRoute() {
|
||||
return <Navigate to="/settings#organization" replace />;
|
||||
}
|
||||
Reference in New Issue
Block a user