Skip to content

Commit 72910fc

Browse files
SaxonFjoshenlim
andauthored
Feat/assistant additions (supabase#30647)
* show thinking if last message is empty * sql toggle copy and border fix * add table and schema context * add suggestions for policy * Add snippet content to ai assistant if on sql editor and assistant is open --------- Co-authored-by: Joshen Lim <[email protected]>
1 parent 2a5072d commit 72910fc

File tree

5 files changed

+51
-7
lines changed

5 files changed

+51
-7
lines changed

apps/studio/components/interfaces/Auth/Policies/PolicyTableRow/PolicyRow.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,14 @@ const PolicyRow = ({
118118
open: true,
119119
sqlSnippets: [sql],
120120
initialInput: `Update the policy with name "${policy.name}" in the ${policy.schema} schema on the ${policy.table} table. It should...`,
121+
suggestions: {
122+
title: `I can help you make a change to the policy "${policy.name}" in the ${policy.schema} schema on the ${policy.table} table, here are a few example prompts to get you started:`,
123+
prompts: [
124+
'Tell me how I can improve this policy...',
125+
'Duplicate this policy for another table...',
126+
'Add extra conditions to this policy...',
127+
],
128+
},
121129
})
122130
}}
123131
>

apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
4040
import AIOnboarding from './AIOnboarding'
4141
import CollapsibleCodeBlock from './CollapsibleCodeBlock'
4242
import { Message } from './Message'
43+
import { useParams } from 'common/hooks'
44+
import { useSearchParamsShallow } from 'common/hooks'
45+
import { useSqlEditorV2StateSnapshot } from 'state/sql-editor-v2'
46+
import { useRouter } from 'next/router'
4347

4448
const MemoizedMessage = memo(
4549
({ message, isLoading }: { message: MessageType; isLoading: boolean }) => {
@@ -71,14 +75,18 @@ export const AIAssistant = ({
7175
className,
7276
onResetConversation,
7377
}: AIAssistantProps) => {
78+
const router = useRouter()
7479
const project = useSelectedProject()
7580
const isOptedInToAI = useOrgOptedIntoAi()
7681
const selectedOrganization = useSelectedOrganization()
82+
const { id: entityId } = useParams()
83+
const searchParams = useSearchParamsShallow()
7784
const includeSchemaMetadata = isOptedInToAI || !IS_PLATFORM
7885

7986
const disablePrompts = useFlag('disableAssistantPrompts')
87+
const { snippets } = useSqlEditorV2StateSnapshot()
8088
const { aiAssistantPanel, setAiAssistantPanel } = useAppStateSnapshot()
81-
const { initialInput, sqlSnippets, suggestions } = aiAssistantPanel
89+
const { open, initialInput, sqlSnippets, suggestions } = aiAssistantPanel
8290

8391
const inputRef = useRef<HTMLTextAreaElement>(null)
8492
const bottomRef = useRef<HTMLDivElement>(null)
@@ -93,6 +101,10 @@ export const AIAssistant = ({
93101
const { data: check } = useCheckOpenAIKeyQuery()
94102
const isApiKeySet = IS_PLATFORM || !!check?.hasKey
95103

104+
const isInSQLEditor = router.pathname.includes('/sql/[id]')
105+
const snippet = snippets[entityId ?? '']
106+
const snippetContent = snippet?.snippet?.content?.sql
107+
96108
const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: selectedOrganization?.slug })
97109
const hasHipaaAddon = subscriptionHasHipaaAddon(subscription)
98110

@@ -102,6 +114,9 @@ export const AIAssistant = ({
102114
schema: 'public',
103115
})
104116

117+
const currentTable = tables?.find((t) => t.id.toString() === entityId)
118+
const currentSchema = searchParams?.get('schema') ?? 'public'
119+
105120
const { mutate: sendEvent } = useSendEventMutation()
106121
const sendTelemetryEvent = (value: string) => {
107122
sendEvent({
@@ -126,6 +141,8 @@ export const AIAssistant = ({
126141
includeSchemaMetadata,
127142
projectRef: project?.ref,
128143
connectionString: project?.connectionString,
144+
schema: currentSchema,
145+
table: currentTable?.name,
129146
},
130147
})
131148

@@ -264,6 +281,20 @@ export const AIAssistant = ({
264281
}
265282
}, [messages, isChatLoading, setAiAssistantPanel])
266283

284+
// Remove suggestions if sqlSnippets were removed
285+
useEffect(() => {
286+
if (!sqlSnippets || sqlSnippets.length === 0) {
287+
setAiAssistantPanel({ suggestions: undefined })
288+
}
289+
}, [sqlSnippets, suggestions, setAiAssistantPanel])
290+
291+
useEffect(() => {
292+
if (open && isInSQLEditor && !!snippetContent) {
293+
setAiAssistantPanel({ sqlSnippets: [snippetContent] })
294+
}
295+
// eslint-disable-next-line react-hooks/exhaustive-deps
296+
}, [open, isInSQLEditor, snippetContent])
297+
267298
if (isLoadingTables) {
268299
return (
269300
<div className="h-full w-full flex justify-center items-center">
@@ -329,7 +360,7 @@ export const AIAssistant = ({
329360
})}
330361
</div>
331362
{renderedMessages}
332-
{last(messages)?.role === 'user' && (
363+
{(last(messages)?.role === 'user' || last(messages)?.content?.length === 0) && (
333364
<motion.div className="text-foreground-lighter text-sm flex gap-1.5 items-center">
334365
<span>Thinking</span>
335366
<div className="flex gap-1">
@@ -363,7 +394,7 @@ export const AIAssistant = ({
363394
</h3>
364395
{suggestions.title && <p>{suggestions.title}</p>}
365396
<div className="-mx-3 mt-4 mb-12">
366-
{suggestions?.prompts.map((prompt) => (
397+
{suggestions?.prompts?.map((prompt) => (
367398
<Button
368399
size="small"
369400
icon={<FileText strokeWidth={1.5} size={16} />}

apps/studio/components/ui/AIAssistantPanel/SqlSnippet.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,9 @@ export const SqlCard = ({
222222
className="w-7 h-7"
223223
icon={<Code size={14} />}
224224
onClick={() => setShowCode(!showCode)}
225-
tooltip={{ content: { side: 'bottom', text: 'Show query' } }}
225+
tooltip={{
226+
content: { side: 'bottom', text: showCode ? 'Hide query' : 'Show query' },
227+
}}
226228
/>
227229

228230
{!isInSQLEditor || isInNewSnippet ? (
@@ -314,7 +316,7 @@ export const SqlCard = ({
314316
value={sql}
315317
language="sql"
316318
className={cn(
317-
'max-w-full max-h-96 block !bg-transparent !py-3 !px-3.5 prose dark:prose-dark border-0 border-t text-foreground !rounded-none w-full',
319+
'max-h-96 max-w-none block !bg-transparent !py-3 !px-3.5 prose dark:prose-dark border-0 border-t text-foreground !rounded-none w-full',
318320
'[&>code]:m-0 [&>code>span]:flex [&>code>span]:flex-wrap [&>code]:block [&>code>span]:text-foreground'
319321
)}
320322
/>

apps/studio/pages/api/ai/sql/generate-v3.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
3939
}
4040

4141
async function handlePost(req: NextApiRequest, res: NextApiResponse) {
42-
const { messages, projectRef, connectionString, includeSchemaMetadata } = req.body
42+
const { messages, projectRef, connectionString, includeSchemaMetadata, schema, table } = req.body
4343

4444
if (!projectRef) {
4545
return res.status(400).json({
@@ -109,6 +109,9 @@ async function handlePost(req: NextApiRequest, res: NextApiResponse) {
109109
- First look at the list of provided schemas and if needed, get more information about a schema. You will almost always need to retrieve information about the public schema before answering a question. If the question is about users, also retrieve the auth schema.
110110
111111
Here are the existing database schema names you can retrieve: ${schemas}
112+
113+
${schema !== undefined ? `The user is currently looking at the ${schema} schema.` : ''}
114+
${table !== undefined ? `The user is currently looking at the ${table} table.` : ''}
112115
`,
113116
messages,
114117
tools: getTools({ projectRef, connectionString, authorization, includeSchemaMetadata }),

apps/studio/state/app-state.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export type CommonDatabaseEntity = {
2222

2323
export type SuggestionsType = {
2424
title: string
25-
prompts: string[]
25+
prompts?: string[]
2626
}
2727

2828
type AiAssistantPanelType = {

0 commit comments

Comments
 (0)