You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: update ClickHouse chat agent example for generative UI (#4251)
Updates the ClickHouse chat agent example page to match the upgraded
example (triggerdotdev/examples#124), which is now a fullstack
generative-UI chat app rather than an agent-only project.
## What changed
- **Overview / tech stack / features** rewritten: Next.js chat app
(`useChat` + `useTriggerChatTransport`, no API route), a
`renderVisualization` tool taking json-render specs rendered with
`@json-render/shadcn` + shadcn charts (Recharts) + mapcn point maps, and
a shared catalog that generates both the system-prompt component
reference and tool-call validation.
- **The agent section** now shows the versioned [AI
Prompt](https://trigger.dev/docs/ai/prompts) pattern (`prompts.define()`
+ `chat.prompt.set()` + `chat.toStreamTextOptions({ registry })`), with
a warning that `experimental_telemetry` comes from the stored prompt —
the docs previously showed a static `system:` string, which silently
ships no LLM observability.
- **New sections** for the shared catalog, the `renderVisualization`
tool, the Next.js chat UI and registry.
- **Relevant code links** updated to the new `src/` layout.
- **Learn more** cards now include Frontend and AI Prompts.
Note: merge after triggerdotdev/examples#124 lands, so the GitHub file
links resolve.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
description: "Build a chat agent that answers questions about your data by writing and running SQL against ClickHouse Cloud, using chat.agent() and the ClickHouse Node.js client."
4
+
description: "Build a chat agent that answers questions about your ClickHouse data with charts, tables and maps instead of text, using chat.agent(), generative UI with json-render, and a Next.js frontend."
5
5
---
6
6
7
7
## Overview
8
8
9
-
This example is a [chat agent](/ai-chat/overview) that answers natural-language questions about the data in a [ClickHouse Cloud](https://clickhouse.com/cloud) database. The agent discovers the schema, writes ClickHouse SQL, runs it through the official [ClickHouse Node.js client](https://clickhouse.com/docs/integrations/javascript), and streams back answers with markdown tables. Trigger.dev handles the chat session, turn loop, streaming, and resumability — the whole agent is one `chat.agent()` call and three tools.
9
+
This example is a fullstack [chat agent](/ai-chat/overview) that answers natural-language questions about the data in a [ClickHouse Cloud](https://clickhouse.com/cloud) database — and presents the answers as **interactive charts, tables, stat cards and maps** instead of walls of text. The agent discovers the schema, writes ClickHouse SQL, runs it through the official [ClickHouse Node.js client](https://clickhouse.com/docs/integrations/javascript), then calls a `renderVisualization` tool with a [json-render](https://json-render.dev) spec that a Next.js chat UI renders live with [shadcn/ui](https://ui.shadcn.com) components.
10
10
11
11
**Tech stack:**
12
12
13
-
-**[Trigger.dev AI chat](/ai-chat/overview)** for the agent session, turn loop, and streaming
13
+
-**[Trigger.dev AI chat](/ai-chat/overview)** for the agent session, turn loop, streaming and resumability
14
+
-**[AI Prompts](/ai/prompts)** for a versioned system prompt with dashboard overrides and per-generation LLM observability
14
15
-**[ClickHouse Node.js client](https://clickhouse.com/docs/integrations/javascript)** (`@clickhouse/client`) for queries over HTTPS
15
-
-**[AI SDK](https://ai-sdk.dev/)** with Anthropic Claude for the model and tool calling
16
+
-**[AI SDK](https://ai-sdk.dev/)** with Anthropic Claude for the model and tool calling, and `useChat` on the frontend
17
+
-**[json-render](https://json-render.dev)** with the [`@json-render/shadcn`](https://www.npmjs.com/package/@json-render/shadcn) component library for generative UI
18
+
-**Next.js** chat app using [`useTriggerChatTransport`](/ai-chat/frontend) — the browser talks directly to Trigger.dev, no API route to maintain
19
+
-**shadcn charts** (Recharts) and **[mapcn](https://mapcn.dev)** (MapLibre GL, free CARTO tiles) for the chart and map components
16
20
17
21
**Features:**
18
22
19
-
-**Schema discovery tools**: `listTables` reads table names, engines, and row counts from `system.tables`; `describeTable` returns column names and types using a bound `Identifier` query param, so table names are never interpolated into SQL strings
23
+
-**Generative UI**: a `renderVisualization` tool takes a json-render spec — bar/line/area/pie charts, data tables, stat-card KPI rows and point maps, composed in cards and grids — with the query results inlined. Specs are validated against the component catalog and errors are returned to the model, so it corrects the spec and retries.
24
+
-**One shared catalog**: the same module generates the system-prompt component reference and validates tool calls, so the prompt and the renderer can't drift apart
25
+
-**Versioned system prompt**: defined with `prompts.define()`, resolvable per-run, overridable from the dashboard without redeploying — and storing it via `chat.prompt.set()` wires up `experimental_telemetry`, so every model call appears in the run trace with token, cost and latency metrics
26
+
-**Schema discovery tools**: `listTables` reads table names, engines and row counts from `system.tables`; `describeTable` returns column names and types using bound `Identifier` query params, so table names are never interpolated into SQL strings
20
27
-**Read-only query tool**: `runQuery` accepts SELECT-style statements only, enforced in code and backed by ClickHouse settings — `readonly=2`, a 1,000-row result cap, and a 30 second execution timeout
21
28
-**Self-correcting SQL**: query errors are returned to the model as tool output, so the agent reads the ClickHouse error, fixes its SQL, and retries
22
-
-**Single environment variable**: the ClickHouse connection is one `CLICKHOUSE_URL` with the credentials embedded, set in the Trigger.dev dashboard
23
29
24
30
## GitHub repo
25
31
@@ -36,25 +42,53 @@ This example is a [chat agent](/ai-chat/overview) that answers natural-language
36
42
37
43
### The agent
38
44
39
-
The agent is defined with [`chat.agent()`](/ai-chat/overview). Tools are declared on the config so tool results survive history re-conversion across turns, and the `run` function returns a `streamText()`call:
45
+
The agent is defined with [`chat.agent()`](/ai-chat/overview). The system prompt is a versioned [AI Prompt](/ai/prompts): the editable analyst guidance lives in the prompt template, while the json-render component reference is generated from the catalog at run time and injected as a template variable. Storing the resolved prompt with `chat.prompt.set()`lets `chat.toStreamTextOptions()` supply the system text, model, config and telemetry:
The system prompt tells the agent to explore the schema before querying, write ClickHouse SQL (not Postgres dialect), prefer aggregations, and present results as markdown tables.
101
+
<Warning>
102
+
On AI SDK v5/v6, `experimental_telemetry` comes from the stored prompt via
103
+
`chat.toStreamTextOptions()` — without `chat.prompt.set()`, model calls don't appear as spans in
104
+
the run trace.
105
+
</Warning>
106
+
107
+
### Generative UI with one shared catalog
108
+
109
+
A single module defines which components the model may use: `Table`, `Card`, `Grid`, `Badge` and friends from `@json-render/shadcn`, plus custom chart components (shadcn charts on Recharts), a `Stat` card, and a `PointMap` built on mapcn. The same catalog produces the system-prompt reference and validates tool calls:
The `renderVisualization` tool accepts a flat json-render spec with the data rows inlined from earlier `runQuery` results. Validation failures go back to the model as tool output:
141
+
142
+
```ts src/trigger/clickhouse-agent.ts
143
+
const renderVisualization =tool({
144
+
description:
145
+
"Render charts, tables and stat cards for the user, instead of describing data as text.",
146
+
inputSchema: z.object({
147
+
spec: z.object({
148
+
root: z.string(),
149
+
elements: z.record(
150
+
z.string(),
151
+
z.object({
152
+
type: z.string(),
153
+
props: z.record(z.string(), z.unknown()),
154
+
children: z.array(z.string()).optional(),
155
+
})
156
+
),
157
+
}),
158
+
}),
159
+
execute: async ({ spec }) => {
160
+
const result =validateSpec(spec);
161
+
if (!result.ok) {
162
+
// The model reads these, fixes the spec, and calls the tool again
163
+
return { ok: false, errors: result.errors };
164
+
}
165
+
return { ok: true, note: "Rendered to the user. Add at most a one-sentence takeaway." };
166
+
},
167
+
});
168
+
```
169
+
170
+
### The Next.js chat UI
171
+
172
+
The frontend uses `useChat` with [`useTriggerChatTransport`](/ai-chat/frontend) — the browser subscribes to the session's streams directly, authenticated by two small server actions. `renderVisualization` tool parts in the message stream render through json-render's `<Renderer>` with the shadcn component registry:
`runQuery` guards against writes twice: a statement allowlist in code, and ClickHouse settings on the request itself. Errors are returned to the model instead of thrown, which is what makes the agent self-correct:
"Run a read-only SQL query against ClickHouse and get the results as JSON rows.",
221
+
description: "Run a read-only SQL query against ClickHouse and get the results as JSON rows.",
79
222
inputSchema: z.object({
80
223
query: z.string().describe("The ClickHouse SQL query to run"),
81
224
}),
@@ -106,35 +249,44 @@ const runQuery = tool({
106
249
});
107
250
```
108
251
109
-
### Connecting to ClickHouse
252
+
### Running it
110
253
111
-
The client reads a single `CLICKHOUSE_URL`environment variable — the HTTPS endpoint with credentials embedded — set in the Trigger.dev dashboard on the [Environment Variables page](/deploy-environment-variables):
254
+
The example needs `CLICKHOUSE_URL`and `ANTHROPIC_API_KEY`set in the Trigger.dev dashboard on the [Environment Variables page](/deploy-environment-variables), and `TRIGGER_PROJECT_REF` plus `TRIGGER_SECRET_KEY` in the local `.env` for the Next.js server actions:
Run `npx trigger.dev@latest dev`, then open the **AI agents** page in the dashboard and chat with `clickhouse-agent` in the playground. With a dataset like [NYC Taxi](https://clickhouse.com/docs/getting-started/example-datasets/nyc-taxi) loaded, asking "What were the top 5 busiest pickup days?" produces a `listTables` call, a `describeTable` call, a SQL aggregation, and a streamed markdown table of results.
268
+
With a dataset like [NYC Taxi](https://clickhouse.com/docs/getting-started/example-datasets/nyc-taxi) loaded, asking for a dashboard of daily trip volume, hourly demand and revenue by payment type produces a stat-card KPI row, two charts and a pie in one composed card — and asking "Where do trips start and end?" produces two interactive maps with size-scaled markers.
126
269
127
270
## Relevant code
128
271
129
-
-**Agent + tools**: [trigger/clickhouse-agent.ts](https://github.com/triggerdotdev/examples/blob/main/clickhouse-chat-agent/trigger/clickhouse-agent.ts): the `chat.agent()` definition, the three tools, the read-only guards, and the ClickHouse client
130
-
-**Trigger config**: [trigger.config.ts](https://github.com/triggerdotdev/examples/blob/main/clickhouse-chat-agent/trigger.config.ts): project config pointing at the `trigger/` directory
272
+
-**Agent + tools**: [src/trigger/clickhouse-agent.ts](https://github.com/triggerdotdev/examples/blob/main/clickhouse-chat-agent/src/trigger/clickhouse-agent.ts): the `chat.agent()` definition, the versioned prompt, the four tools, the read-only guards, and the ClickHouse client
273
+
-**Shared catalog**: [src/lib/catalog.ts](https://github.com/triggerdotdev/examples/blob/main/clickhouse-chat-agent/src/lib/catalog.ts): component definitions, prompt-reference generation, and spec validation
274
+
-**Component registry**: [src/lib/registry.tsx](https://github.com/triggerdotdev/examples/blob/main/clickhouse-chat-agent/src/lib/registry.tsx): maps catalog components to shadcn/Recharts/mapcn implementations
0 commit comments