Skip to content
AI

Conversation

The thread, the turn, the generative border and the composer — the four pieces of an assistant that can be read as a record rather than a chat.

The thread

What can I build on 42 Jarrah Street?
GRIDD AI09:14
The lot is in Riverton's Low–medium density residential zone. A dwelling house is accepted development; a dual occupancy is code assessable under Table 5.5.5.1.
What about the flood overlay?
GRIDD AI09:15
I cannot tell you — the flood overlay is not one of this project's four layers, so there is nothing for me to read. Load it and ask again. I will not estimate it from the surrounding lots.
Which of my layers do overlap the site?
GRIDD AI09:15
Two of the four: Lots and Road reserve. Vegetation and Contours do not intersect the site boundary at all.

Enter to send · Shift + Enter for a new line

Two behaviours worth trying: scroll up mid-answer and the thread stops chasing the bottom until you return, and the person's turn is a bubble while the assistant's takes the whole column.
Code
<GdAiThread :revision="revision">
  <GdAiMessage v-for="t in turns" :key="t.id" :from="t.from" :at="t.at">
    {{ t.text }}
  </GdAiMessage>
  <GdAiMessage v-if="generating" generating>Reading the ruleset…</GdAiMessage>
</GdAiThread>

<GdAiComposer v-model="draft" :generating="generating" @send="ask" />

Generative border

Riverton City Plan 2020 · Table 5.5.5.1 · reading zone rules for the selected lot…

Reading the ruleset

Reading the ruleset
Active generation only, never decoration, and never two indicators at once. One hue rather than a mosaic: a GRIDD screen already has a council's zone palette on it, and a multi-colour animated edge beside a choropleth is the loudest thing in the view and means the least.
Code
<GdAiGenerating active label="Reading the ruleset">
  <p>The answer, as it arrives…</p>
</GdAiGenerating>

Composer

Enter to send · Shift + Enter for a new line

A textarea rather than an input even though most questions are one line: a single-line input silently truncates the visible text of a long question at the moment a person most wants to re-read it — and “what can I build on 42 Jarrah Street if the flood overlay applies” is not short. field-sizing grows it with no ResizeObserver.
Code
<GdAiComposer v-model="draft" @send="ask" @stop="abort" />

API

GdAiThread

Props

PropTypeDefault
revisionnumber0

A count that changes when a turn is added or a token streams. The thread follows the tail when it changes — a number rather than the messages, so the caller keeps its own data shape.

labelstring"Conversation"

The accessible name of the log.

GdAiMessage

Props

PropTypeDefault
from"person" | "assistant""assistant"

Who is speaking. The two do NOT mirror — a person gets a right-aligned bubble, the assistant gets the full column. See Why this way.

namestring"GRIDD AI"

Shown beside the mark on an assistant turn. Override it when a named skill answered — "Certifier check" reads better than the product name when that is what ran.

atstring—

A timestamp, already formatted. Set in mono and quiet. Format it absolutely: a relative time in a record goes stale the moment the record is read back.

generatingboolean—

The model is still writing this turn. Draws the generative border around the body.

Slots

default

The turn's content. On an assistant turn this is prose from a model and gets the column's measure, list and paragraph spacing.

sources

A GdAiSources below the answer. Below, never above: a reader wants the answer first and the evidence when they doubt it.

actions

Feedback controls. Deliberately the caller's — what a thumb-down DOES is product policy, and a design system that shipped the handler would be deciding it.

GdAiGenerating

Props

PropTypeDefault
activeboolean—

Is a model producing content right now? This is the ONLY thing this component may mean.

labelstring"Generating"

What is being produced, in three or four words. Announced to assistive tech and shown in the reduced-motion form. A generic "Loading" wastes the one chance to say what the wait is for.

quietboolean—

Hide the visible label. The accessible one still fires — it is the only signal a screen reader gets.

GdAiComposer

Props

PropTypeDefault
modelValuestring—

The question being typed, as v-model. Cleared on send.

placeholderstring"Ask about this project…"

Ask a real question. "Type a message…" teaches nothing about what this assistant can answer.

generatingboolean—

A model is producing an answer — Ask becomes Stop. One control in one place, whose label says what pressing it does now.

disabledboolean—

No session, no project loaded, over quota.

labelstring"Ask the assistant"

The field's accessible name. A placeholder is not one — it vanishes the moment the user types.

Events

sendstring

The trimmed question. Enter sends; Shift+Enter breaks the line; an IME's composing Enter does neither.

stopvoid

Abandon the generation in flight. A first-class control: a generation costs money and seconds, and a person who can see it going wrong in the first line should not wait out the other twelve.

Behavior & Anatomy

The two turns do not mirror

A person's turn is short and is a record of what they asked; a bubble suits it and the alignment makes the thread scannable. The assistant's turn is the answer, and in this product an answer runs to paragraphs, a table of controls, a citation list. Putting that in a bubble narrows the measure, breaks tables, and makes the reply look like an opinion rather than a document. It is content, so it gets the column.

The thread follows the tail only when you are at the tail

A log that always scrolls to the bottom yanks the page out from under someone who scrolled up to re-read an earlier answer — which, when an answer is a paragraph of planning reasoning, is exactly what people do while the next one streams. So it pins while you are at the bottom and stops the moment you leave. scroll-behavior: smooth is deliberately not used: fired on every streamed token it becomes a permanent slow slide.

Stop is a control, not a nicety

A generation costs money and takes seconds. The send button becomes stop rather than sitting beside it — one control, in one place, whose label says what pressing it does now.

Navigate

Esc