AI Chat
A conversational panel for asking the AI analyst questions. It renders a
role-based message layout, starter prompts, a live status / typing
indicator, and a slide-in trace view that reveals what each turn did. In
the app it is wired to the fusion-analyst api backend; on its own it falls
back to a self-contained stub.
:::info Backend wiring
The widget talks to the api durable run engine: each message is sent as
POST /api/runs, and the reply is streamed back over SSE
(GET /api/runs/{id}/events). agent.* events drive the status line;
message.delta chunks render a live, growing assistant bubble; and
message.completed finalizes the reply once run.completed arrives.
agent.*, tool.*, and report.section_completed events are also captured
as ordered trace steps for the turn (see below).
The backend origin is read from VITE_API_BASE (default
http://127.0.0.1:8787). When no transport is supplied (e.g. previews and
tests), the panel uses a local stub that echoes a canned reply.
:::
At a glance
| Type key | ai-chat |
| Default size | 4 × 12 (min 3 × 6) |
| Data source | api runs + SSE (VITE_API_BASE) |
| Emits | chat:command (map commands + apply-cypher from an assistant turn) |
| Receives | — |
| Source | src/widgets/widgets/ai-chat/ |
Configuration
None — ai-chat is dataless and exposes no config panel. The backend origin
is configured globally via the VITE_API_BASE environment variable.
Cross-widget actions
When an assistant turn carries commands (e.g. "zoom to this location"), the
backend surfaces them as ui.command SSE events. The transport validates each
against the ChatCommand schema
(untrusted LLM output — malformed commands are dropped) and the widget emits the
turn's accumulated commands on the chat:command trigger.
The Actions panel routes these to one or more Map or 3D Scene
widgets via the map-command effect ("When the assistant sends a command → Run
on map"). The target applies each command once with view.goTo. See
Cross-widget actions for the runtime
flow.
Connect a Knowledge Graph (Link Chart)
The Actions panel also lets you connect the chat to a single Link Chart
on the same view (the link-chart-command effect, "Connect a Knowledge Graph").
Only one graph can back a conversation at a time, so selecting a chart replaces
any previous connection.
When connected, each turn sends workflow: "knowledge_graph" and the chart's
knowledgeGraphItemId (as client_context.knowledge_graph_context.item_id) to
the backend. The knowledge_graph workflow loads the graph (and its optional
kg-ai-metadata.json authoring hints), then decides whether to run an openCypher
query, a Lucene search, or answer conversationally, executing reads
read-only.
For openCypher the planner produces two purpose-built queries: a visualization
query that returns a subgraph (entities + relationships — the only thing the
chart can render) and, for count/statistic questions, an optional analytic
query (an aggregate like count(...)) for an exact figure. The summary uses
the analytic result for precise numbers and the subgraph for concrete examples,
and only the subgraph query is pushed to the chart via apply-cypher (an
aggregate would leave the chart empty). When the graph's authoring metadata
describes which property names an entity or relationship type (for example a
description marking a property as its name or title), the planner also emits a
label map alongside the query — type → property — so the chart labels those
nodes and relationships by the chosen property instead of its default field.
Lucene searches are summarized in chat only. See
Link Chart and
Cross-widget actions.
Notable behavior
- Shows a set of starter prompts when the conversation is empty.
- Sends each message to the
apibackend and streams the reply over SSE, surfacing agent progress as a live status line and rendering token deltas into a growing assistant bubble. - Defaults to the real conversational analyst (
demo_mode: false); a deterministic demo simulator is available as a credential-free fallback. - Forwards the signed-in user's ArcGIS token (
Authorization: Bearer) and portal URL (client_context.arcgis_portal_url) to the backend so server-side tools (e.g. geocoding) run as that user. The token is read lazily at the start of each turn, so it always reflects the current, short-lived credential. - Backend or network failures are surfaced inline as an assistant message.
- Without a transport (previews/tests) it falls back to a canned stub reply.
Trace view
Each assistant turn captures an ordered trace of what it did — agent progress, tool calls, and report sections — derived from the backend event stream. The transport maps events to trace steps as follows:
| Event | Trace step |
|---|---|
agent.started / agent.progress / agent.status | info — the reported task (with an optional detail) |
tool.started | query — Tool: <name> (or a backend-supplied label) |
tool.completed | compute — Finished <name> (with the tool's duration) |
tool.failed | warn — Tool failed: <name> (with the error) |
report.section_completed | render — Section: <title> |
Each step records a durationMs (the backend's own value when available,
otherwise the wall-clock time since the previous step), and the turn records a
total thoughtMs.
A step may also carry a detail — a longer, secondary string the backend
attaches for drill-down (for example the exact query that ran, or the error
text). The transport prefers backend-supplied label and detail fields when
present, falling back to generic text otherwise.
Progressive disclosure
The trace is designed to read top-down as a clean, high-level outline. Steps
that carry a detail render their label as an expandable toggle (a chevron
that rotates open); the detail stays collapsed by default and reveals as a
monospace block when clicked. Steps without a detail render as plain labels.
This lets a turn surface a concise summary first while keeping the underlying
specifics one click away.
For example, a knowledge graph turn emits high-level steps such as "Opened the knowledge graph" (with a hint about whether authoring metadata was loaded), "Planned a graph query", "Running visualization query (openCypher)" (whose detail is the generated query text), "Updated the Link Chart", and "Writing the answer".
When a turn has a trace, a "Thought for X" affordance appears beneath the reply. Clicking it slides the trace drawer in over the conversation; a back button at the top returns to the chat. While a turn is still running, the affordance reads "Thinking… (X)" and opens a live trace that ticks and grows as new steps stream in.
The trace primitives (TraceStep, formatThoughtTime, TracePanel) are
exported from the widget module for reuse.