Skip to content

Add ClickHouse chat agent example#123

Merged
matt-aitken merged 1 commit into
mainfrom
clickhouse-chat-agent
Jul 8, 2026
Merged

Add ClickHouse chat agent example#123
matt-aitken merged 1 commit into
mainfrom
clickhouse-chat-agent

Conversation

@matt-aitken

@matt-aitken matt-aitken commented Jul 8, 2026

Copy link
Copy Markdown
Member

What

A new example: clickhouse-chat-agent — a chat agent that answers questions about your data by writing and running SQL against ClickHouse Cloud, using the official Node.js ClickHouse client.

  • listTables / describeTable / runQuery tools (AI SDK tool() + Zod)
  • Read-only guard: SELECT-only statements enforced in code, plus readonly=2, a 1,000-row cap and 30s timeout via ClickHouse settings
  • describeTable uses a bound Identifier query param (no SQL string interpolation)
  • Query errors are returned to the model so the agent fixes its SQL and retries

Testing

Typechecked against @trigger.dev/sdk 4.5.1 and run end-to-end against a ClickHouse Cloud service loaded with the NYC Taxi example dataset — schema discovery, aggregations and markdown-table answers all work in the agent playground.

Companion docs PR: triggerdotdev/trigger.dev#4195 (links to this folder — merge this one first).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a ClickHouse chat agent that can list tables, inspect table structure, and run controlled SQL queries.
    • Added project setup for Trigger.dev, including runtime, scripts, and TypeScript configuration.
  • Documentation
    • Added setup, deployment, and example prompt instructions in the project README.
    • Added environment variable guidance and placeholders for required configuration.
  • Chores
    • Updated ignore rules for local dependencies, environment files, and Trigger.dev artifacts.

A chat.agent() with listTables/describeTable/runQuery tools backed by
the ClickHouse Node.js client. Read-only query guards enforced in code
and via ClickHouse settings (readonly=2, row cap, execution timeout).
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

This PR adds a new example project, clickhouse-chat-agent, implementing a Trigger.dev-based chat agent that answers questions using ClickHouse. It includes project configuration files (package.json, tsconfig.json, trigger.config.ts, .gitignore, .env.example), an agent implementation providing listTables, describeTable, and runQuery tools with read-only query enforcement and output truncation, a streaming run handler using Claude Opus, and a README with setup and usage instructions.

Estimated code review effort: 3 (Moderate) | ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: adding a ClickHouse chat agent example.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch clickhouse-chat-agent

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@clickhouse-chat-agent/trigger/clickhouse-agent.ts`:
- Around line 80-96: The current read-only guard in runQuery only checks
statement prefixes, so it still allows queries to override limits with SETTINGS
and call outbound table functions. Tighten the ClickHouse agent’s query path by
enforcing immutable user/profile-level caps for max rows and execution time, and
add a locked-down allowlist/blocklist for table functions such as url, s3,
remote, mysql, and postgres within runQuery (or the underlying ClickHouse
user/config used by it). Keep the existing READ_ONLY_STATEMENTS check, but make
the real restriction come from the ClickHouse profile/user configuration and
explicit table-function filtering.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 345dd6d8-ad46-4e2c-b0d1-4184a968f2f8

📥 Commits

Reviewing files that changed from the base of the PR and between 2f88f1a and c7e0397.

⛔ Files ignored due to path filters (1)
  • clickhouse-chat-agent/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (7)
  • clickhouse-chat-agent/.env.example
  • clickhouse-chat-agent/.gitignore
  • clickhouse-chat-agent/README.md
  • clickhouse-chat-agent/package.json
  • clickhouse-chat-agent/trigger.config.ts
  • clickhouse-chat-agent/trigger/clickhouse-agent.ts
  • clickhouse-chat-agent/tsconfig.json

Comment on lines +80 to +96
const READ_ONLY_STATEMENTS = /^\s*(select|with|show|describe|desc|explain|exists)\b/i;

const runQuery = tool({
description:
"Run a read-only SQL query against ClickHouse and get the results as JSON rows. " +
"Only SELECT-style statements are allowed. Always include a LIMIT (at most 100 rows) " +
"unless the query is an aggregation.",
inputSchema: z.object({
query: z.string().describe("The ClickHouse SQL query to run"),
}),
execute: async ({ query }) => {
if (!READ_ONLY_STATEMENTS.test(query)) {
return {
error:
"Only read-only statements (SELECT, WITH, SHOW, DESCRIBE, EXPLAIN, EXISTS) are allowed.",
};
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Does ClickHouse readonly=2 allow a query-level SETTINGS clause to override max_result_rows and max_execution_time that were supplied as client clickhouse_settings, and which table functions (url, s3, remote, mysql, postgres) are permitted under readonly=2 on ClickHouse Cloud?

💡 Result:

Yes, in ClickHouse, a query-level SETTINGS clause can be used to override settings such as max_result_rows and max_execution_time, provided the user has the necessary permissions [1]. Under the readonly=2 setting, users are permitted to change settings (excluding the readonly setting itself), which enables them to modify query-level constraints [2][3][4]. Regarding table functions (url, s3, remote, mysql, postgres) under readonly=2: 1. Permission Requirement: Many table functions that access external data—such as url, s3, remote, mysql, and postgres—require the CREATE TEMPORARY TABLE permission to execute because they may involve temporary metadata or connection handling [5][6]. 2. readonly=2 Functionality: The readonly=2 setting explicitly allows users to execute SET and CREATE TEMPORARY TABLE queries [2]. Consequently, users with readonly=2 are generally permitted to use these table functions, whereas users with readonly=1 (which restricts these actions) are typically blocked from using them [5][6][7]. 3. ClickHouse Cloud: While ClickHouse Cloud follows standard ClickHouse permission models, specific cloud-managed security policies or constraints (often enforced via user profiles or settings constraints) may further restrict the use of certain table functions regardless of the readonly setting to maintain platform security. Users should verify their specific service-level configuration or documentation if encountering access issues, as external data access might be governed by additional cloud-side controls.

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the target file and related references.
git ls-files | rg '^clickhouse-chat-agent/trigger/clickhouse-agent\.ts$|clickhouse_settings|readonly|max_result_rows|max_execution_time|allowed_table_functions|table function|runQuery|tool\('

# Show the relevant section of the target file with line numbers.
sed -n '1,220p' clickhouse-chat-agent/trigger/clickhouse-agent.ts

# Search for other query-execution/settings code that may affect this behavior.
rg -n "clickhouse_settings|readonly|max_result_rows|max_execution_time|allowed_table_functions|SETTINGS|url\(|s3\(|remote\(|mysql\(|postgres\(" clickhouse-chat-agent -S

Repository: triggerdotdev/examples

Length of output: 7083


readonly=2 still leaves the query limits and network surface overrideable.
SELECT-only parsing doesn’t stop a prompt from adding SETTINGS max_result_rows=0, max_execution_time=0 or using outbound table functions like url()/s3()/remote()/mysql()/postgres(). Use an immutable profile/user-level restriction for the caps and a locked-down table-function allowlist instead of relying on per-query settings.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@clickhouse-chat-agent/trigger/clickhouse-agent.ts` around lines 80 - 96, The
current read-only guard in runQuery only checks statement prefixes, so it still
allows queries to override limits with SETTINGS and call outbound table
functions. Tighten the ClickHouse agent’s query path by enforcing immutable
user/profile-level caps for max rows and execution time, and add a locked-down
allowlist/blocklist for table functions such as url, s3, remote, mysql, and
postgres within runQuery (or the underlying ClickHouse user/config used by it).
Keep the existing READ_ONLY_STATEMENTS check, but make the real restriction come
from the ClickHouse profile/user configuration and explicit table-function
filtering.

@matt-aitken matt-aitken merged commit cd5e9fd into main Jul 8, 2026
3 checks passed
@matt-aitken matt-aitken deleted the clickhouse-chat-agent branch July 8, 2026 18:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants