mirror of
https://github.com/supabase/supabase.git
synced 2026-10-08 19:05:06 +03:00
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Feature — final PR (9/9) of the SQL editor logs-source stack. **Base branch:** `charislam/sql-editor-inline-ai-clickhouse-dialect` (PR 8). Nothing here is user-visible: entry points stay behind `sqlEditorLogsSource` + `otelLegacyLogs`, and flag rollout happens after the whole stack merges. ## What is the current behavior? - The Assistant has no idea a SQL editor snippet targets the logs backend. Ask it about a logs snippet and it answers in Postgres, because the attached query is fenced as ` ```sql ` and nothing tells the model otherwise. - Because the `sql` fence is what `MessageMarkdown` treats as runnable Postgres, an attached ClickHouse query is rendered with a Run-against-Postgres affordance and branded with `untrustedSql`. - "Debug with Assistant" on a failed logs query produces a dialect-less prompt, so both the in-app assistant and the copyable version get debugged as Postgres. - A report referencing a `log_sql` snippet runs its ClickHouse SQL against the user's Postgres database and surfaces the resulting error. ## What is the new behavior? **Assistant panel.** The "Current Query" chip records which backend the attached query targets. That reaches the model two ways: each attachment is fenced with its own dialect (` ```clickhouse ` vs ` ```sql `), and a `containsLogsSnippets` flag rides on the user message as AI SDK `metadata`. The server reads the flag off the conversation and prepends the ClickHouse dialect rules plus the logs schema reference as a non-cached context message. Two design points worth calling out in review: - The flag lives on the **message**, not the request body, so Retry and the tool-approval continuation reproduce the context a message was originally asked in — neither of those passes a per-call body. - It's derived from **what's actually attached**, so detaching the chip drops the claim rather than leaving the two able to disagree. The `clickhouse` fence also keeps a logs query out of `MessageMarkdown`'s `sql` branch, so it's no longer offered as runnable Postgres or branded with `untrustedSql` — a boundary this stack's distinct brands exist to prevent crossing. **Debug flow.** `buildDebugChatArgs` attaches its query with a source for the same reason, and names the dialect in the prompt text so the copyable version stands on its own outside the app. **Reports.** A report only stores a snippet id, so whether it queries the logs backend is only knowable once the content loads. `ReportBlock` guards on the fetched type and renders a `LogsSnippetReportBlock` placeholder instead of executing. Double-guarded: no `sql` for a logs snippet (so it's out of the query key and `queryFn` short-circuits even on an explicit `refetch`) and `enabled` excludes it. **Incidental cleanups.** `buildAssistantContextMessages` extracted out of `generate-assistant-response`; a schema-access sentinel that was duplicated as a string literal across two files (and compared against) replaced with one exported constant; `SqlSnippet` deduplicated to a single declaration; `resolveSnippetSource` / `isLogsSource` shared instead of re-implemented per surface. **Tests.** 4 new/extended suites. Notable cases pinned: a message with no metadata must validate (`safeValidateUIMessages` applies `metadataSchema` to *every* message, so a required schema would 400 every existing conversation); only *user* messages count, so a model reply can't talk the server into a different dialect; a mixed-attachment message is flagged without overclaiming a single source; and `ReportBlock` registers no pg-meta mock for the logs cases, so an unhandled request failing the test *is* the assertion that logs SQL never reaches Postgres. Verified: `pnpm typecheck`, `lint:ratchet` (no regression), Prettier, and the full Studio suite (459 files / 4969 tests). ## Additional context <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added support for recognizing log snippets in reports, with clear guidance to open them in the SQL editor or remove them. - AI Assistant now understands log snippets and provides ClickHouse-specific context, formatting, and troubleshooting guidance. - Snippets retain their source information when shared with the AI Assistant. - **Bug Fixes** - Prevented unsupported log snippets from being executed as regular database queries. - Improved source detection when opening snippets directly from links. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
80 lines
3.6 KiB
TypeScript
80 lines
3.6 KiB
TypeScript
import {
|
|
buildClickhouseLogsSchemaSection,
|
|
CLICKHOUSE_LOGS_COMPLETION_INSTRUCTIONS,
|
|
} from '@/lib/ai/clickhouse-logs'
|
|
|
|
/**
|
|
* Stands in for the schema list when the org hasn't opted into sharing schemas.
|
|
* Doubles as a sentinel — "no project context worth sending" is decided by
|
|
* comparing against this exact sentence — so the producer and the comparison have
|
|
* to agree on it, hence one exported constant instead of copies per call site.
|
|
*/
|
|
export const NO_SCHEMA_ACCESS_MESSAGE = "You don't have access to any schemas."
|
|
|
|
/**
|
|
* A request-scoped context message, sent as an assistant turn ahead of the
|
|
* conversation. Deliberately NOT part of the system prompt: the system prompt is
|
|
* static so Bedrock can cache it, and anything derived from the current project,
|
|
* chat, or open editor tab would break that cache.
|
|
*/
|
|
export type AssistantContextMessage = { role: 'assistant'; content: string }
|
|
|
|
/**
|
|
* Tells the model that the snippet in the SQL editor targets the logs backend, so
|
|
* SQL it writes for that snippet comes back as ClickHouse for the `logs` table
|
|
* rather than Postgres. Carries the same dialect rules and table reference the
|
|
* inline editor completions use, so there's one description of the logs schema.
|
|
*/
|
|
function buildLogsSnippetContext(): string {
|
|
return [
|
|
"Some SQL snippets are marked with the dialect 'clickhouse', which means they query the Supabase logs backend, not the Postgres database. Any SQL you write, edit, or debug for that snippet must be ClickHouse SQL against the logs table described below — the database schema and the Postgres tools don't apply to it. You can help a user iterate on their ClickHouse SQL query, but you cannot run it for them (the execute_query tool does not run log queries). Postgres SQL is still the right answer for anything else the user asks about their database, or for non-ClickHouse marked queries.",
|
|
CLICKHOUSE_LOGS_COMPLETION_INSTRUCTIONS.trim(),
|
|
buildClickhouseLogsSchemaSection().trim(),
|
|
].join('\n\n')
|
|
}
|
|
|
|
/**
|
|
* Assemble the context messages that precede the conversation: what project and
|
|
* chat this is, whether it's a support chat, and which backend the open SQL editor
|
|
* snippet targets. Pure and per-request — see {@link AssistantContextMessage} for
|
|
* why none of this belongs in the system prompt.
|
|
*/
|
|
export function buildAssistantContextMessages({
|
|
projectRef,
|
|
chatName,
|
|
schemasString,
|
|
supportMode,
|
|
includesLogsSnippets,
|
|
}: {
|
|
projectRef?: string
|
|
chatName?: string
|
|
schemasString: string
|
|
supportMode?: boolean
|
|
/** Whether any user message in the conversation attached a logs (ClickHouse) query. */
|
|
includesLogsSnippets?: boolean
|
|
}): AssistantContextMessage[] {
|
|
const messages: AssistantContextMessage[] = []
|
|
|
|
const hasProjectContext = !!projectRef || !!chatName || schemasString !== NO_SCHEMA_ACCESS_MESSAGE
|
|
if (hasProjectContext) {
|
|
messages.push({
|
|
role: 'assistant',
|
|
content: `The user's current project is ${projectRef || 'unknown'}. Their available schemas are: ${schemasString}. The current chat name is: ${chatName || 'unnamed'}.`,
|
|
})
|
|
}
|
|
|
|
if (supportMode) {
|
|
messages.push({
|
|
role: 'assistant',
|
|
content:
|
|
'This is an active support chat. Help the user while they wait for a human agent. Keep guidance practical and concise. If the user asks for a human, or if the issue cannot be safely resolved, call escalate_to_human with a short reason. Only call resolve_support_conversation after the user explicitly confirms the issue is resolved; otherwise keep helping.',
|
|
})
|
|
}
|
|
|
|
if (includesLogsSnippets) {
|
|
messages.push({ role: 'assistant', content: buildLogsSnippetContext() })
|
|
}
|
|
|
|
return messages
|
|
}
|