diff --git a/apps/studio/components/ui/AIAssistantPanel/AIAssistant.prompts.ts b/apps/studio/components/ui/AIAssistantPanel/AIAssistant.prompts.ts
new file mode 100644
index 00000000000..8274e777d8e
--- /dev/null
+++ b/apps/studio/components/ui/AIAssistantPanel/AIAssistant.prompts.ts
@@ -0,0 +1,42 @@
+export const defaultPrompts = [
+ {
+ title: 'Create a back-end',
+ prompt:
+ 'Create a messaging app with users, messages, and an edge function that uses OpenAI to summarize message threads.',
+ },
+ {
+ title: 'Health check',
+ prompt: 'Can you check if my database and edge functions are healthy?',
+ },
+ {
+ title: 'Query your data',
+ prompt: 'Give me a list of new users from the auth.users table who signed up in the past week',
+ },
+ {
+ title: 'Set up RLS policies',
+ prompt: 'Create RLS policies to ensure users can only access their own data',
+ },
+ {
+ title: 'Create a function',
+ prompt: 'Create an edge function that summarises the contents of a table row using OpenAI',
+ },
+ {
+ title: 'Generate sample data',
+ prompt: 'Generate sample data for a blog with users, posts, and comments tables',
+ },
+]
+
+export const codeSnippetPrompts = [
+ {
+ title: 'Explain code',
+ prompt: 'Explain what this code does and how it works',
+ },
+ {
+ title: 'Improve code',
+ prompt: 'How can I improve this code for better performance and readability?',
+ },
+ {
+ title: 'Debug issues',
+ prompt: 'Help me debug any potential issues with this code',
+ },
+]
diff --git a/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx b/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx
index 55889cafcbe..04f9fde6376 100644
--- a/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx
+++ b/apps/studio/components/ui/AIAssistantPanel/AIAssistant.tsx
@@ -22,14 +22,14 @@ import uuidv4 from 'lib/uuid'
import { useAiAssistantStateSnapshot } from 'state/ai-assistant-state'
import { useSqlEditorV2StateSnapshot } from 'state/sql-editor-v2'
import { AiIconAnimation, Button, cn } from 'ui'
-import { Admonition, AssistantChatForm, GenericSkeletonLoader } from 'ui-patterns'
+import { Admonition, GenericSkeletonLoader } from 'ui-patterns'
import { ButtonTooltip } from '../ButtonTooltip'
import { ErrorBoundary } from '../ErrorBoundary'
import { onErrorChat } from './AIAssistant.utils'
import { AIAssistantChatSelector } from './AIAssistantChatSelector'
import { AIOnboarding } from './AIOnboarding'
import { AIOptInModal } from './AIOptInModal'
-import { CollapsibleCodeBlock } from './CollapsibleCodeBlock'
+import { AssistantChatForm } from './AssistantChatForm'
import { Message } from './Message'
import { useAutoScroll } from './hooks'
import type { AssistantMessageType } from 'state/ai-assistant-state'
@@ -246,34 +246,20 @@ export const AIAssistant = ({ className }: AIAssistantProps) => {
const hasMessages = chatMessages.length > 0
const isShowingOnboarding = !hasMessages && isApiKeySet
- const sendMessageToAssistant = (content: string) => {
- let finalContent = content
-
- // Handle SQL snippets based on opt-in level
- if (aiOptInLevel !== 'disabled') {
- const sqlSnippetsString =
- snap.sqlSnippets?.map((snippet: string) => '```sql\n' + snippet + '\n```').join('\n') || ''
- finalContent = [content, sqlSnippetsString].filter(Boolean).join('\n\n')
- } else {
- snap.setSqlSnippets([])
- }
-
+ const sendMessageToAssistant = (finalContent: string) => {
const payload = {
role: 'user',
createdAt: new Date(),
content: finalContent,
id: uuidv4(),
} as MessageType
+
snap.clearSqlSnippets()
-
- // Store the user message in the ref before appending
lastUserMessageRef.current = payload
-
append(payload)
-
setValue('')
- if (content.includes('Help me to debug')) {
+ if (finalContent.includes('Help me to debug')) {
sendEvent({
action: 'assistant_debug_submitted',
groups: {
@@ -552,23 +538,6 @@ export const AIAssistant = ({ className }: AIAssistantProps) => {
{!isShowingOnboarding && (
- {snap.sqlSnippets && snap.sqlSnippets.length > 0 && (
-
- {snap.sqlSnippets.map((snippet: string, index: number) => (
- {
- const newSnippets = [...(snap.sqlSnippets ?? [])]
- newSnippets.splice(index, 1)
- snap.setSqlSnippets(newSnippets)
- }}
- className="text-xs rounded-b-none border-b-0"
- />
- ))}
-
- )}
{disablePrompts && (
{
textarea]:text-base [&>textarea]:md:text-sm [&>textarea]:border-1 [&>textarea]:rounded-md [&>textarea]:!outline-none [&>textarea]:!ring-offset-0 [&>textarea]:!ring-0'
+ 'z-20 [&>form>textarea]:text-base [&>form>textarea]:md:text-sm [&>form>textarea]:border-1 [&>form>textarea]:rounded-md [&>form>textarea]:!outline-none [&>form>textarea]:!ring-offset-0 [&>form>textarea]:!ring-0'
)}
loading={isChatLoading}
disabled={!isApiKeySet || disablePrompts || isChatLoading}
@@ -607,13 +576,18 @@ export const AIAssistant = ({ className }: AIAssistantProps) => {
: 'Chat to Postgres...'
}
value={value}
- autoFocus
onValueChange={(e) => setValue(e.target.value)}
- onSubmit={(event) => {
- event.preventDefault()
- sendMessageToAssistant(value)
+ onSubmit={(finalMessage) => {
+ sendMessageToAssistant(finalMessage)
scrollToEnd()
}}
+ sqlSnippets={snap.sqlSnippets as string[] | undefined}
+ onRemoveSnippet={(index) => {
+ const newSnippets = [...(snap.sqlSnippets ?? [])]
+ newSnippets.splice(index, 1)
+ snap.setSqlSnippets(newSnippets)
+ }}
+ includeSnippetsInMessage={aiOptInLevel !== 'disabled'}
/>
)}
diff --git a/apps/studio/components/ui/AIAssistantPanel/AIOnboarding.tsx b/apps/studio/components/ui/AIAssistantPanel/AIOnboarding.tsx
index d6b7aa3617d..a8b6a505c18 100644
--- a/apps/studio/components/ui/AIAssistantPanel/AIOnboarding.tsx
+++ b/apps/studio/components/ui/AIAssistantPanel/AIOnboarding.tsx
@@ -1,10 +1,10 @@
import { motion } from 'framer-motion'
-import { Code, FileText, Heart, MessageCircleMore, Shield, WandSparkles } from 'lucide-react'
+import { FileText } from 'lucide-react'
import { useRef } from 'react'
import { Button, cn } from 'ui'
-import { AssistantChatForm } from 'ui-patterns'
-import { CollapsibleCodeBlock } from './CollapsibleCodeBlock'
+import { AssistantChatForm } from './AssistantChatForm'
+import { codeSnippetPrompts, defaultPrompts } from './AIAssistant.prompts'
interface AIOnboardingProps {
onMessageSend: (message: string) => void
@@ -28,60 +28,6 @@ export const AIOnboarding = ({
}: AIOnboardingProps) => {
const inputRef = useRef(null)
- const defaultPrompts = [
- {
- title: 'Create a back-end',
- prompt:
- 'Create a messaging app with users, messages, and an edge function that uses OpenAI to summarize message threads.',
- icon: ,
- },
- {
- title: 'Health check',
- prompt: 'Can you check if my database and edge functions are healthy?',
- icon: ,
- },
- {
- title: 'Query your data',
- prompt:
- 'Give me a list of new users from the auth.users table who signed up in the past week',
- icon: ,
- },
- {
- title: 'Set up RLS policies',
- prompt: 'Create RLS policies to ensure users can only access their own data',
- icon: ,
- },
- {
- title: 'Create a function',
- prompt: 'Create an edge function that summarises the contents of a table row using OpenAI',
- icon: ,
- },
- {
- title: 'Generate sample data',
- prompt: 'Generate sample data for a blog with users, posts, and comments tables',
- icon: ,
- },
- ]
-
- const codeSnippetPrompts = [
- {
- title: 'Explain code',
- prompt: 'Explain what this code does and how it works',
- icon: ,
- },
- {
- title: 'Improve code',
- prompt: 'How can I improve this code for better performance and readability?',
- icon: ,
- },
- {
- title: 'Debug issues',
- prompt: 'Help me debug any potential issues with this code',
- icon: ,
- },
- ]
-
- // Use suggestions if available, otherwise use code-specific prompts if snippets exist, or default prompts
const prompts = suggestions?.prompts
? suggestions.prompts.map((suggestion) => ({
title: suggestion.label,
@@ -105,37 +51,26 @@ export const AIOnboarding = ({
How can I assist you?
- {sqlSnippets && sqlSnippets.length > 0 && (
-
- {sqlSnippets.map((snippet: string, index: number) => (
- onRemoveSnippet?.(index)}
- className="text-xs rounded-b-none border-b-0 text-left"
- />
- ))}
-
- )}
textarea]:text-base [&>textarea]:md:text-sm [&>textarea]:border-1 [&>textarea]:rounded-md [&>textarea]:!outline-none [&>textarea]:!ring-offset-0 [&>textarea]:!ring-0'
+ 'z-20 [&>form>textarea]:text-base [&>form>textarea]:md:text-sm [&>form>textarea]:border-1 [&>form>textarea]:rounded-md [&>form>textarea]:!outline-none [&>form>textarea]:!ring-offset-0 [&>form>textarea]:!ring-0'
)}
loading={false}
disabled={false}
placeholder="Ask me anything..."
value={value}
onValueChange={(e) => onValueChange(e.target.value)}
- onSubmit={(event) => {
- event.preventDefault()
- if (value.trim()) {
- onMessageSend(value)
+ onSubmit={(finalMessage) => {
+ if (finalMessage.trim()) {
+ onMessageSend(finalMessage)
onValueChange('')
}
}}
- autoFocus
+ sqlSnippets={sqlSnippets}
+ onRemoveSnippet={onRemoveSnippet}
+ snippetsClassName="text-left"
+ includeSnippetsInMessage={true}
/>
@@ -149,7 +84,6 @@ export const AIOnboarding = ({
>