Menu
Public repository / beddeb15df67607b460f8291beb5c20f68db988e
AkurAI-Framework / site/content/docs/ai-artifacts.md
Latest change 8847e6f4a315fb27eba8cb69b87397dd08a068eb - feat(ai/artifacts): add Chart, DataTable, CodeBlock, CodeDiff ES modules by Ólafur Búi Ólafsson
# AI Artifacts
Tool-result components in the **Artifacts** category render rich, interactive content
directly inside an assistant message — no bundler, no library.
Each component is a vanilla ES module at
`site/frontend/ai/components/artifacts/<name>.js` exporting a single `def` object:
```js
export const def = {
name, // machine identifier
category, // "Artifacts"
title, // human label
match(payload), // returns true when this component owns the payload
render(payload, ctx), // returns an HTMLElement — pure DOM, no innerHTML on user data
example, // sample payload for preview/docs
};
```
The runtime calls `match` on every registered component in order.
The first match wins; on no match the payload falls back to a JSON code view.
---
## Chart
**File:** `site/frontend/ai/components/artifacts/chart.js`
**Name:** `chart`
Renders a bar, line, or pie chart as **native inline SVG** — no charting library.
Axis labels, gridlines, and brand accent colours come from CSS custom properties.
### Payload
```ts
{
type: 'bar' | 'line' | 'pie';
labels: string[]; // one label per data point
series: number[] // single series shorthand
| { label: string; data: number[] }[]; // multi-series
}
```
### Chart types
| `type` | Renders |
|--------|---------|
| `bar` | Grouped vertical bars, one colour per series |
| `line` | Connected polyline with dots, one colour per series |
| `pie` | Filled segments + percentage legend (first series only) |
### SVG approach
- ViewBox `360×220` (bar/line) or `300×200` (pie); scales to container width via `width:100%`.
- Margins: L 50 px (Y-axis labels), B 40 px (X-axis labels), T 16 px, R 16 px.
- Y axis: 4 even gridlines; labels from `Math.round(max×1.1 × i/4)`.
- Bar width is 72 % of the per-group slot, shared across series.
- Line: `<polyline>` + `<circle>` dots per data point.
- Pie: `<path>` arc segments using `M cx,cy L x1,y1 A r,r,0,large,1,x2,y2 Z`; angles start at 12 o'clock.
- Palette: `['#5b8cff','#3ddc84','#f5b945','#8a6bff','#58b2ff','#ff6b6b']` — wraps on overflow.
### Examples
```json
{ "type": "bar", "labels": ["Jan","Feb","Mar"], "series": [12,19,8] }
```
```json
{
"type": "line",
"labels": ["Q1","Q2","Q3","Q4"],
"series": [
{ "label": "Revenue", "data": [40,55,72,90] },
{ "label": "Costs", "data": [30,38,44,51] }
]
}
```
```json
{
"type": "pie",
"labels": ["Direct","Organic","Referral"],
"series": [45, 30, 25]
}
```
---
## Data Table
**File:** `site/frontend/ai/components/artifacts/data_table.js`
**Name:** `data_table`
Renders tabular data using the framework's `.table` class.
Click any column header to sort ascending; click again to reverse.
Numeric columns are right-aligned with tabular figures.
### Payload
```ts
{
columns: string[]; // header labels
rows: any[][]; // each row is an array aligned to columns
}
```
Column type is inferred: a column is numeric when every non-empty cell converts to
a finite number.
### Example
```json
{
"columns": ["Name", "Score", "Rank"],
"rows": [
["Alice", 92, 1],
["Bob", 87, 2],
["Carol", 78, 3]
]
}
```
---
## Code Block
**File:** `site/frontend/ai/components/artifacts/code_block.js`
**Name:** `code_block`
Renders a code card with a language badge, optional filename, a **Copy** button,
and lightweight syntax highlighting.
### Payload
```ts
{
language: string; // e.g. "javascript", "rust", "sql"
code: string;
filename?: string; // optional — shown next to the badge
}
```
### Highlighting
HTML-escape runs first; token colouring is then layered on top with `<span
style="color:…">` wrappers. This guarantees XSS safety: user-supplied code is
always escaped before any string manipulation.
Token order (first match wins, no overlaps):
| Token | Colour |
|-------|--------|
| Strings (`"…"`, `'…'`, `` `…` ``) | `#3ddc84` |
| Comments (`// … `, `/* … */`, `# …`) | `#5c647a` |
| Keywords (`const`, `fn`, `return`, …) | `#8a6bff` |
| Numbers (`42`, `3.14`, `1e6`) | `#f5b945` |
The Copy button writes `payload.code` to the clipboard via the Clipboard API.
### Example
```json
{
"language": "javascript",
"filename": "greet.js",
"code": "const greet = async (name) => {\n return `Hello, ${name}!`;\n};"
}
```
---
## Code Diff
**File:** `site/frontend/ai/components/artifacts/code_diff.js`
**Name:** `code_diff`
Renders a red/green line-level diff. Accepts either a **unified diff string** or a
structured **hunks array**.
### Payload
Structured hunks:
```ts
{
filename?: string;
hunks: {
old: string[]; // removed lines
new: string[]; // added lines
}[];
}
```
Or a unified diff string (output of `git diff` / `diff -u`):
```ts
{
filename?: string;
diff: string; // unified diff; --- / +++ headers are skipped
}
```
### Rendering
| Line type | Background | Gutter | Text colour |
|-----------|-----------|--------|-------------|
| Deleted (`-`) | red tint | `−` red | `#ffb3b3` |
| Added (`+`) | green tint | `+` green | `#b3f0d0` |
| Hunk header (`@@`) | blue tint | — | `#5c647a` italic |
| Context | transparent | — | `#8a93a8` |
All line text is set via `textContent` — XSS-safe.
### Example (hunks)
```json
{
"filename": "src/greet.js",
"hunks": [
{
"old": ["function greet(name) {", " return 'Hello ' + name;", "}"],
"new": ["const greet = (name) => {", " return `Hello, ${name}!`;", "};"]
}
]
}
```
### Example (unified diff)
```json
{
"filename": "src/greet.js",
"diff": "@@ -1,3 +1,3 @@\n-function greet(name) {\n- return 'Hello ' + name;\n-}\n+const greet = (name) => {\n+ return `Hello, ${name}!`;\n+};"
}
```