diff --git a/src/components/chat/ChatInput.tsx b/src/components/chat/ChatInput.tsx index 14c04d7..2983324 100644 --- a/src/components/chat/ChatInput.tsx +++ b/src/components/chat/ChatInput.tsx @@ -38,6 +38,7 @@ import { SuggestedAction, ProposalResult, FileChange, + SqlQuery, } from "@/lib/schemas"; import type { Message } from "@/ipc/ipc_types"; import { isPreviewOpenAtom } from "@/atoms/viewAtoms"; @@ -547,7 +548,7 @@ function ProposalSummary({ packagesAdded = [], filesChanged = [], }: { - sqlQueries?: string[]; + sqlQueries?: Array; serverFunctions?: FileChange[]; packagesAdded?: string[]; filesChanged?: FileChange[]; @@ -600,9 +601,12 @@ function ProposalSummary({ } // SQL Query item with expandable functionality -function SqlQueryItem({ query }: { query: string }) { +function SqlQueryItem({ query }: { query: SqlQuery }) { const [isExpanded, setIsExpanded] = useState(false); + const queryContent = query.content; + const queryDescription = query.description; + return (
  • - SQL Query + + {queryDescription || "SQL Query"} +
    {isExpanded ? ( @@ -623,7 +629,9 @@ function SqlQueryItem({ query }: { query: string }) {
    {isExpanded && (
    - {query} + + {queryContent} +
    )}
  • diff --git a/src/components/chat/DyadExecuteSql.tsx b/src/components/chat/DyadExecuteSql.tsx index 8c204b0..50b7ad3 100644 --- a/src/components/chat/DyadExecuteSql.tsx +++ b/src/components/chat/DyadExecuteSql.tsx @@ -14,16 +14,19 @@ import { CustomTagState } from "./stateTypes"; interface DyadExecuteSqlProps { children?: ReactNode; node?: any; + description?: string; } export const DyadExecuteSql: React.FC = ({ children, node, + description, }) => { const [isContentVisible, setIsContentVisible] = useState(false); const state = node?.properties?.state as CustomTagState; const inProgress = state === "pending"; const aborted = state === "aborted"; + const queryDescription = description || node?.properties?.description; return (
    = ({
    - SQL Query + {queryDescription || "SQL Query"} {inProgress && (
    diff --git a/src/ipc/handlers/proposal_handlers.ts b/src/ipc/handlers/proposal_handlers.ts index 2f8acb5..d0c1dec 100644 --- a/src/ipc/handlers/proposal_handlers.ts +++ b/src/ipc/handlers/proposal_handlers.ts @@ -3,6 +3,7 @@ import type { CodeProposal, FileChange, ProposalResult, + SqlQuery, } from "../../lib/schemas"; import { db } from "../../db"; import { messages } from "../../db/schema"; @@ -105,7 +106,11 @@ const getProposalHandler = async ( })), ]; // Check if we have enough information to create a proposal - if (filesChanged.length > 0 || packagesAdded.length > 0) { + if ( + filesChanged.length > 0 || + packagesAdded.length > 0 || + proposalExecuteSqlQueries.length > 0 + ) { const proposal: CodeProposal = { type: "code-proposal", // Use parsed title or a default title if summary tag is missing but write tags exist @@ -113,7 +118,10 @@ const getProposalHandler = async ( securityRisks: [], // Keep empty filesChanged, packagesAdded, - sqlQueries: proposalExecuteSqlQueries, + sqlQueries: proposalExecuteSqlQueries.map((query) => ({ + content: query.content, + description: query.description, + })), }; logger.log( "Generated code proposal. title=", diff --git a/src/ipc/processors/response_processor.ts b/src/ipc/processors/response_processor.ts index 9256b2c..8566358 100644 --- a/src/ipc/processors/response_processor.ts +++ b/src/ipc/processors/response_processor.ts @@ -15,6 +15,7 @@ import { executeSupabaseSql, } from "../../supabase_admin/supabase_management_client"; import { isServerFunction } from "../../supabase_admin/supabase_utils"; +import { SqlQuery } from "../../lib/schemas"; const readFile = fs.promises.readFile; const logger = log.scope("response_processor"); @@ -108,14 +109,18 @@ export function getDyadChatSummaryTag(fullResponse: string): string | null { return null; } -export function getDyadExecuteSqlTags(fullResponse: string): string[] { +export function getDyadExecuteSqlTags(fullResponse: string): SqlQuery[] { const dyadExecuteSqlRegex = - /([\s\S]*?)<\/dyad-execute-sql>/g; + /]*)>([\s\S]*?)<\/dyad-execute-sql>/g; + const descriptionRegex = /description="([^"]+)"/; let match; - const queries: string[] = []; + const queries: { content: string; description?: string }[] = []; while ((match = dyadExecuteSqlRegex.exec(fullResponse)) !== null) { - let content = match[1].trim(); + const attributesString = match[1] || ""; + let content = match[2].trim(); + const descriptionMatch = descriptionRegex.exec(attributesString); + const description = descriptionMatch?.[1]; // Handle markdown code blocks if present const contentLines = content.split("\n"); @@ -127,7 +132,7 @@ export function getDyadExecuteSqlTags(fullResponse: string): string[] { } content = contentLines.join("\n"); - queries.push(content); + queries.push({ content, description }); } return queries; @@ -209,11 +214,11 @@ export async function processFullResponseActions( try { const result = await executeSupabaseSql({ supabaseProjectId: chatWithApp.app.supabaseProjectId!, - query, + query: query.content, }); } catch (error) { errors.push({ - message: `Failed to execute SQL query: ${query}`, + message: `Failed to execute SQL query: ${query.content}`, error: error, }); } diff --git a/src/lib/schemas.ts b/src/lib/schemas.ts index e3f254c..e29e250 100644 --- a/src/lib/schemas.ts +++ b/src/lib/schemas.ts @@ -132,13 +132,18 @@ export interface FileChange { isServerFunction: boolean; } +export interface SqlQuery { + content: string; + description?: string; +} + export interface CodeProposal { type: "code-proposal"; title: string; securityRisks: SecurityRisk[]; filesChanged: FileChange[]; packagesAdded: string[]; - sqlQueries: string[]; + sqlQueries: SqlQuery[]; } export interface SuggestedAction { diff --git a/src/prompts/supabase_prompt.ts b/src/prompts/supabase_prompt.ts index fdf756a..922d176 100644 --- a/src/prompts/supabase_prompt.ts +++ b/src/prompts/supabase_prompt.ts @@ -89,12 +89,14 @@ function Login() { ## Database -If the user wants to use the database, use the following code: +If the user wants to use the database, use the following syntax: - + SELECT * FROM users; +The description should be a short description of what the code is doing and be understandable by semi-technical users. + You will need to setup the database schema. ## Creating User Profiles @@ -103,7 +105,7 @@ If the user wants to create a user profile, use the following code: ### Create profiles table in public schema - + CREATE TABLE public.profiles ( id UUID NOT NULL REFERENCES auth.users ON DELETE CASCADE, first_name TEXT, @@ -130,7 +132,7 @@ create policy "Users can update own profile." on profiles for update using ( aut ### Function to insert profile when user signs up - + CREATE FUNCTION public.handle_new_user() RETURNS TRIGGER LANGUAGE PLPGSQL