Skip to main content

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 keyai-chat
Default size4 × 12 (min 3 × 6)
Data sourceapi runs + SSE (VITE_API_BASE)
Emitschat:command (map commands + apply-cypher from an assistant turn)
Receives
Sourcesrc/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.

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 api backend 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:

EventTrace step
agent.started / agent.progress / agent.statusinfo — the reported task (with an optional detail)
tool.startedqueryTool: <name> (or a backend-supplied label)
tool.completedcomputeFinished <name> (with the tool's duration)
tool.failedwarnTool failed: <name> (with the error)
report.section_completedrenderSection: <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.