Full-page assistant
A2AChat is the same chat UI as the floating widget, but it sits in your page
layout. Use it for a /chat or /assistant page, or inside a dashboard.
It uses the same two server routes as the floating widget (/api/a2a and
/api/a2a/config). If you’ve already followed the
chatbot guide, the server side is done.
"use client";
import { A2AChat } from "@gnomondigital/nebulas-kit-react";
export default function ChatPage() { return ( <div className="container mx-auto max-w-4xl py-8 px-4"> <A2AChat a2aEndpoint="/api/a2a" configEndpoint="/api/a2a/config" labels={{ title: "Assistant", description: "Ask anything about our products", newChat: "New chat", placeholder: "Ask anything…", }} suggestedPrompts={[ "Summarize our return policy", "Which plan fits a team of 10?", ]} showAttachFileButton /> </div> );}Layout
Section titled “Layout”layout="page"(default): the chat takes the height of the viewport.layout="panel": the chat fills its parent. Use it in a sidebar, tab or card that has a fixed height:
<div className="h-[600px] rounded-lg border"> <A2AChat layout="panel" a2aEndpoint="/api/a2a" configEndpoint="/api/a2a/config" /></div>Record conversations in Nebulas
Section titled “Record conversations in Nebulas”By default the chat only talks to the agent. To also save each conversation
and its messages in your Nebulas project (so you can review them in Nebulas),
pass nebulasBaseUrl. It points at a proxy route for the Nebulas conversation
API:
-
Add the catch-all Nebulas proxy. It needs a signed-in session because it writes records on behalf of a user:
src/app/api/nebulas/[...path]/route.ts import "@/lib/nebulas";import { createNebulasProxyHandler } from "@gnomondigital/nebulas-kit-core/nextjs";import { auth0 } from "@/lib/auth";const handler = createNebulasProxyHandler({auth: auth0,audience: process.env.AUTH0_A2A_AUDIENCE,apiKey: process.env.NEBULAS_API_KEY,});export const GET = handler;export const POST = handler;export const PUT = handler;export const PATCH = handler;export const DELETE = handler; -
Pass the route to the component:
<A2AChata2aEndpoint="/api/a2a"configEndpoint="/api/a2a/config"nebulasBaseUrl="/api/nebulas"user={{ name: user.name, picture: user.picture }}/>
The first message creates a conversation in the project that /api/a2a/config
returns (nebulasProjectId). The following messages are added to it. New
chat starts a new conversation.
Login form in the browser (browser ROP)
Section titled “Login form in the browser (browser ROP)”For quick internal tools, you can let people sign in from the page and send
their token with each chat request. useA2AAuth keeps the token in
sessionStorage:
"use client";import { A2AChat, useA2AAuth } from "@gnomondigital/nebulas-kit-react";
export default function InternalChat() { const { token, login, error, isLoading } = useA2AAuth({ authEndpoint: "/api/a2a/auth", });
if (!token) { return ( <form onSubmit={(e) => { e.preventDefault(); const f = new FormData(e.currentTarget); login(String(f.get("username")), String(f.get("password"))).catch(() => {}); // shown via `error` }} > <input name="username" /> <input name="password" type="password" /> <button disabled={isLoading}>Sign in</button> {error && <p>{error}</p>} </form> ); }
return ( <A2AChat a2aEndpoint="/api/a2a" configEndpoint="/api/a2a/config" getAuthHeaders={() => ({ Authorization: `Bearer ${token}` })} authDependency={token} // reloads the config after login /> );}authEndpoint is a route you write. It receives POST { username, password },
exchanges them with your identity provider (for example the Auth0 password
grant), and returns { "access_token": "…" }. On failure, return a non-2xx
status with { "error": "…" }.
