CI / build (push) Successful in 4m26s
Adds a Postgres-backed quotes domain (poems/quotes/favorites) exposed as five agent-native actions (list-quotes, get-random-quote, create-quote, toggle-favorite, list-favorites) callable from both chat and the React UI via useActionQuery/useActionMutation. Moves the primary UI from chat to a mobile-first Quotes/Favorites experience (chat moves to /chat), adds manual OpenTelemetry instrumentation exporting traces/metrics/logs over OTLP, and wires a local Docker Postgres for shared state.
95 lines
2.8 KiB
TypeScript
95 lines
2.8 KiB
TypeScript
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 = `Chat - ${APP_TITLE}`;
|
|
const SEO_DESCRIPTION =
|
|
"Ask the agent to look up, add, or organize poem quotes in Verse.";
|
|
|
|
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)}` : "/chat";
|
|
}
|
|
|
|
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>
|
|
);
|
|
}
|