<AgentChat />
The complete chat experience out of the box:
- message bubbles with lightweight markdown (code blocks, tables, lists, bold), a typing indicator and streaming cursor
- a collapsible live activity feed (
thinking → acting → observing → responding) attached to each assistant message - a welcome screen with suggested starter prompts
- a geometry attach panel (point / polyline / polygon)
- voice input — a mic button for dictating messages (Web Speech API)
- per-message actions: copy, read aloud (TTS) and export as PDF
- chat history — a slide-over of saved sessions (search, rename, delete,
new chat), backed by
localStorage - a capacity queue overlay when the server reports HTTP 503 (usage ring, retry countdown, cancel) with automatic retries
- a stop button (cancel) while a run is in flight
- the HitL approval modal with auto-reject countdown and optional rejection reason
- an auth / feature-gate overlay (
locked) that blocks all interaction
import { AgentChat } from "stacgis-ai-react";
import "stacgis-ai-react/dist/index.css";
export function MapAgent() {
return (
<AgentChat
apiBaseUrl="http://localhost:8000/api/v1"
title="GeoAgent"
placeholder="Ask me to geocode, route or buffer…"
onFrontendEvent={(event) => {
if (event.event_name === "zoom_to") myMap.flyTo(event.payload);
}}
/>
);
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
apiBaseUrl | string | http://localhost:8000 | Agent API base URL (no trailing /agent) |
title | string | AI Orchestrator Chat | Header title |
placeholder | string | Ask the AI agent anything… | Textarea placeholder |
mode | "stream" | "chat" | "stream" | SSE streaming vs blocking (set by the host app; no built-in switch) |
theme | "light" | "dark" | "dark" | Colour theme (set by the host app; no built-in toggle) |
approvalTimeoutMs | number | 120000 | HitL modal auto-reject countdown (also sent to the backend as approval_timeout_s) |
suggestedPrompts | SuggestedPrompt[] | 4 geospatial defaults | Starter prompts for the welcome screen — pass [] to show only the hero (passing custom prompts is how the demo app drives the "What to try" list) |
enableHistory | boolean | true | Persist chat sessions in localStorage and show the history panel (disable with false) |
autoSpeak | boolean | false | Read the final assistant answer aloud automatically once the run completes (toggleable in the UI via the speaker button) |
renderChart | (spec: unknown) => React.ReactNode | — | Custom renderer for ```chart markdown blocks whose body is JSON — plug in your own chart library; without it the block is rendered as a JSON code block |
locked | boolean | false | Lock the chat behind an auth/feature gate — an overlay is shown and every interaction is blocked until you set it to false again |
lockTitle | string | AI Assistant | Overlay heading |
lockMessage | string | Sign in to unlock the assistant and start chatting. | Overlay body copy |
lockCtaLabel | string | Continue | CTA button label (button rendered only when onLockedClick is set) |
onLockedClick | () => void | — | Called when the user clicks the gate's CTA (e.g. open your sign-up) |
onFrontendEvent | (e: FrontendToolEvent) => void | — | Handle @frontend_tool UI events (see Frontend tool events) |
className | string | — | Extra classes on the container |
SuggestedPrompt is { icon: string; text: string } — the emoji/glyph plus
the prompt text sent verbatim when clicked.
Programmatic sending (ref)
AgentChat is a forwardRef component exposing an imperative
AgentChatHandle:
import { useRef } from "react";
import { AgentChat, type AgentChatHandle } from "stacgis-ai-react";
const chatRef = useRef<AgentChatHandle>(null);
// e.g. the user picked a location on your map — hand it to the agent:
chatRef.current?.send(`I picked lat=${lat}, lon=${lon}. Continue with that.`);
<AgentChat ref={chatRef} apiBaseUrl="http://localhost:8000/api/v1" />;
send(text) is a no-op while a run is in flight, while the request is queued
(server at capacity), or while the chat is locked. This is how the demo app
wires the map location picker back into the agent.
Internal composition
AgentChat is composed of the smaller building blocks, all of which are
exported if you want to build a custom layout:
| Component | Purpose |
|---|---|
MessageBubble | A single message: markdown, attachment badges, per-message actions (copy, read aloud via onSpeak/onStopSpeaking, export as PDF — lazy-loads jspdf + html-to-image), and the attached steps feed |
MarkdownRenderer (+ parseBlocks) | Lightweight markdown used by bubbles: headings, bold/italic, inline code, fenced code (incl. chart blocks via renderChart), lists, tables, links, blockquotes |
SuggestedPrompts | Welcome screen with clickable starter prompts (title/subtitle + prompt list) |
ChatHistory | Slide-over session history: search, rename, delete, new chat, relative timestamps |
ChatQueueOverlay | Server-at-capacity overlay: usage ring (active/max slots), retry countdown, cancel |
AgentActivityFeed / ActivityFeed | Live ReAct step feed (thinking / acting / observing / responding) |
TypingIndicator / GradientArc | Streaming affordances (typing dots, avatar spinner) |
ApprovalModal | Rendered automatically while pendingApproval is set — tool name, arguments table, auto-reject countdown, optional rejection reason |
Sessions are persisted automatically when a run completes (title = first user
message, truncated to 60 chars) via the useChatSessions
hook.