AI chat

A chat app with a history sidebar (new-chat button, rename, delete, and a footer profile card that opens a settings modal), streaming replies, and forkable reply threads in a resizable side panel. Installs as a folder with ToolCallTrace and Questionnaire as dependencies. Works with a real API: chats, threads, replies, and search all load from API routes, so point them at your own backend.

Installation

npx dafink-ui add ai-chat

Also installs: Sidebar, Scroll-fade, Message, Typewriter, Attachment, Button, Input, Textarea, Command-input, Command-palette, Badge, Tooltip, Spinner, Collapsible, Timeline, Modal, Charts, Function-plotter, Table, Date-picker, Slider, Formula, Code-block, Audioplayer, Skeleton, Questionnaire, Tool-call-trace, Resizable, Workflow-builder, Avatar, Select, Switch

Requires: react-markdown, remark-gfm, remark-math

Demo

Loading…

Prompt

This block's demo replies are canned — no model is called. To make a real LLM produce content this block already knows how to render, add the following to your own system prompt.

Most of your reply can just be normal GitHub-flavored markdown — the chat already
renders it: **bold**/*italic*, [links](https://example.com), `inline code`, fenced code blocks
(```js ... ```, any language), bullet/numbered lists, and pipe tables all render with this
app's real UI components, not raw text. None of that needs special instructions; it's what
you already produce for any markdown-aware client.

Two things are NOT standard markdown and must be explained in the system prompt if you want
the model to use them:

1. Math formulas — inline with single dollars, block with double dollars, standard LaTeX:
   Inline: The area is $\pi r^2$.
   Block:  $$x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$$

2. Charts — markdown has no chart syntax, so these stay a fenced code block convention.
   When a visual would genuinely help (a trend, a comparison, a breakdown) — for a quick
   fact, prefer prose or a markdown table instead — use a fenced block in one of these
   languages, containing JSON in the exact shape shown. If the request needs real data you
   don't already have, use a search or data tool first rather than inventing numbers:

   - "lineplot"   — a trend over a continuous axis (time, distance, ...)
     { "xKey": string, "series": [{ "key": string, "label": string }], "data": [{ ...one object per point, with an xKey field and a field per series key... }] }

   - "barchart"   — comparing discrete categories. Same shape as lineplot, plus an optional "stacked": true to stack series instead of grouping them
     { "xKey": string, "series": [...], "data": [...], "stacked"?: boolean }

   - "areachart"  — volume or a cumulative total over time. Same shape as barchart (including optional "stacked")
     { "xKey": string, "series": [...], "data": [...], "stacked"?: boolean }

   - "radarchart" — comparing several categories against one another, optionally across more than one series. Same shape as lineplot
     { "xKey": string, "series": [...], "data": [...] }

   - "donutchart" — a simple part-to-whole breakdown. No xKey/series — just labeled slices
     { "data": [{ "label": string, "value": number }] }

   - "math"       — plotting one or more mathematical functions of x as a graph (not a formula — use $$...$$ for that)
     { "equations": string[] }   // e.g. ["x^2 - 2", "sin(x)"] — plain math expressions in x, evaluated with mathjs syntax, no "y =" prefix

3. Media — a generated image or audio clip also has no markdown syntax, so these are fenced
   too. Only emit one once you actually have a real URL for it (e.g. after a generation
   tool call resolves) — while that's in flight, the consuming app is expected to show its
   own loading state, not you.

   - "image" — a generated or fetched image
     { "url": string, "alt": string }

   - "audio" — a generated or fetched audio clip
     { "src": string, "title"?: string }

4. Workflows — a node-based diagram of a process (an automation, a pipeline, a decision
   flow). Renders as a static, horizontal box-and-wire diagram — no toolbar, no run/simulate
   control, not draggable or editable — it's for showing the shape of a process, not
   executing or changing it. Each node has zero or more named input ports and zero or more
   named output ports; a node with no inputs is an entry point, one with no outputs is
   terminal, and a node with 2+ outputs is a branch (give each output a distinct id/label,
   e.g. "pass"/"fail"):

   - "workflow"
     {
       "nodes": [{ "id": string, "label": string, "description"?: string,
                   "inputs": [{ "id": string, "label": string }],
                   "outputs": [{ "id": string, "label": string }],
                   "position": { "x": number, "y": number } }],
       "edges": [{ "id": string, "source": string, "target": string,
                   "sourceHandle": string, "targetHandle": string }]
     }
     Space nodes left-to-right in the order they run (roughly 260px per step is readable);
     "sourceHandle"/"targetHandle" must match an id from that node's own outputs/inputs.

Example:

User: How has the median home price changed over the last few years?
Assistant: Here's the trend in median home prices over the last several years:

```lineplot
{"xKey":"year","series":[{"key":"price","label":"Median home price"}],"data":[{"year":2019,"price":313000},{"year":2020,"price":329000},{"year":2021,"price":375000},{"year":2022,"price":395000},{"year":2023,"price":410000},{"year":2024,"price":426000}]}
```

The chart/media fence conventions and the $...$/$$...$$ math delimiters aren't something
the model already knows to use unprompted — this block must be included in the system
prompt on every request, not just the first turn. Everything else above it is included
for completeness, not because it needs teaching.