mirror of
https://github.com/stack-auth/stack.git
synced 2026-07-20 21:29:36 +08:00
Add filter-analytics-table system prompt for row filters.
Constrain AI search to SELECT * FROM <table> WHERE ... so analytics table views keep the same columns. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
a21139958c
commit
fbfa37c63d
@ -44,11 +44,15 @@ export const SYSTEM_PROMPT_IDS = [
|
||||
"create-dashboard",
|
||||
"run-query",
|
||||
"build-analytics-query",
|
||||
"filter-analytics-table",
|
||||
"rewrite-template-source",
|
||||
] as const;
|
||||
export type SystemPromptId = typeof SYSTEM_PROMPT_IDS[number];
|
||||
|
||||
/**
|
||||
* Schema documentation for the analytics ClickHouse tables, shared by every
|
||||
* prompt that generates SQL against them ("build-analytics-query") so the two can never drift apart.
|
||||
* prompt that generates SQL against them ("build-analytics-query" and
|
||||
* "filter-analytics-table") so the two can never drift apart.
|
||||
*/
|
||||
const ANALYTICS_TABLES_SCHEMA_DOC = `### DATA SCHEMA (project/branch filtering is automatic — do NOT add WHERE project_id = ...)
|
||||
|
||||
@ -236,8 +240,6 @@ Key insights: No timestamp column — do NOT attempt \`ORDER BY created_at\` or
|
||||
| provider_account_id | String | External account identifier |
|
||||
| created_at | DateTime64(3, 'UTC') | Link time |`;
|
||||
|
||||
export type SystemPromptId = typeof SYSTEM_PROMPT_IDS[number];
|
||||
|
||||
/**
|
||||
* Context-specific system prompts that are appended to the base prompt.
|
||||
* These should be concise and focus on the specific use case.
|
||||
@ -1313,6 +1315,46 @@ GROUP BY date, event_type ORDER BY date DESC, event_count DESC LIMIT 100
|
||||
- If the user refers to a previous query, modify it incrementally — don't start from scratch.
|
||||
- If \`queryAnalytics\` returns an error, adjust and retry. Do NOT invent columns or fabricate data.
|
||||
- If the user asks about event types or data that don't exist in the schema above, explain what IS available and generate the closest useful query instead.
|
||||
`,
|
||||
|
||||
"filter-analytics-table": `
|
||||
## Context: Analytics Table Row Filter
|
||||
|
||||
You power the search bar above a data grid on the Hexclave analytics page. The grid shows every column of ONE table (\`SELECT * FROM <table>\`), and the user typed a request that a plain substring search can't express. Your ONLY job is to narrow down WHICH ROWS are shown — the set of columns must never change. The table the user is viewing is stated at the start of the conversation.
|
||||
|
||||
**HARD RULES — query shape:**
|
||||
Call \`queryAnalytics\` with a query of EXACTLY this shape:
|
||||
|
||||
\`SELECT * FROM <table> WHERE <condition>\`
|
||||
|
||||
1. The query MUST start with \`SELECT * FROM <table>\` for the exact table the user is viewing. The frontend validates this shape and rejects anything else.
|
||||
2. After the table name, only a \`WHERE\` clause is allowed at the top level — no column lists, aliases, aggregates, GROUP BY, ORDER BY, LIMIT, JOIN, or UNION. The grid layers sorting and pagination on top itself.
|
||||
3. Subqueries INSIDE the WHERE condition are allowed and encouraged for cross-table filters, e.g. \`WHERE toString(id) IN (SELECT user_id FROM events WHERE ...)\`. Mind the types: \`users.id\` is a UUID while \`events.user_id\` is a String, so wrap the UUID side in \`toString()\`.
|
||||
4. Do NOT paste SQL into chat text in place of a tool call — the UI only picks up tool calls, and only after you come to a complete stop, so avoid chatty responses.
|
||||
5. You only see a small preview of the results in the tool output — the user sees the full filtered table in the grid.
|
||||
6. If \`queryAnalytics\` returns an error, fix the condition and retry.
|
||||
7. If the user refines the filter (e.g. "only verified ones"), modify your previous WHERE condition incrementally.
|
||||
8. If the request CANNOT be expressed as a row filter on this table (e.g. it asks for aggregations, trends, grouped counts, joins that add columns, or data from a different table), do NOT call the tool. Reply with ONE short sentence explaining why, and if possible suggest the closest row filter you COULD apply instead.
|
||||
|
||||
${ANALYTICS_TABLES_SCHEMA_DOC}
|
||||
|
||||
### CRITICAL SQL RULES
|
||||
|
||||
1. **JSON extraction REQUIRES toString() wrapper:**
|
||||
- CORRECT: \`JSONExtractString(toString(data), 'path')\`
|
||||
- WRONG: \`JSONExtractString(data, 'path')\` — this WILL FAIL
|
||||
2. **Nested JSON uses dot notation:** \`JSONExtractString(toString(data), 'ip_info.country_code')\`
|
||||
3. SELECT queries only — no INSERT / UPDATE / DELETE / DDL
|
||||
4. Use relative date ranges (\`now() - INTERVAL X DAY\`) and ClickHouse date helpers: toDate(), toStartOfDay(), toStartOfWeek(), toStartOfMonth()
|
||||
5. team_id is always NULL — never filter on it
|
||||
6. Prefer case-insensitive matching (\`ILIKE '%...%'\`) for user-typed text unless the user clearly means an exact value
|
||||
|
||||
### EXAMPLES (user is viewing \`users\`)
|
||||
|
||||
- "signed up in the last 7 days" → \`SELECT * FROM users WHERE signed_up_at >= now() - INTERVAL 7 DAY\`
|
||||
- "verified gmail accounts" → \`SELECT * FROM users WHERE primary_email_verified = 1 AND primary_email ILIKE '%@gmail.com%'\`
|
||||
- "people with a page view this week" → \`SELECT * FROM users WHERE toString(id) IN (SELECT user_id FROM events WHERE event_type = '$page-view' AND event_at >= now() - INTERVAL 7 DAY)\`
|
||||
- "signups per day last month" → no tool call; explain that's an aggregation this view can't display, and offer e.g. "show signups from last month" as a filter instead.
|
||||
`,
|
||||
|
||||
"rewrite-template-source": `You rewrite email template TSX source into standalone draft TSX.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user