| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 |
- import { streamText, tool } from 'ai'
- import { source } from 'common-tags'
- import { NextApiRequest, NextApiResponse } from 'next'
- import { z } from 'zod'
- import { getModel } from '@/lib/ai/model'
- import { DEFAULT_COMPLETION_MODEL } from '@/lib/ai/model.utils'
- import apiWrapper from '@/lib/api/apiWrapper'
- export const maxDuration = 60
- const ServiceSchema = z.object({
- name: z.enum(['Auth', 'Storage', 'Database', 'Edge Function', 'Cron', 'Queues', 'Vector']),
- reason: z.string().describe("The reason why this service is needed for the user's use case"),
- })
- const getTools = () => {
- return {
- executeSql: tool({
- description: 'Save the generated database schema definition',
- inputSchema: z.object({
- sql: z.string().describe('The SQL schema definition'),
- }),
- }),
- reset: tool({
- description: 'Reset the database, services and start over',
- inputSchema: z.object({}),
- }),
- setServices: tool({
- description:
- 'Set the entire list of Briven services needed for the project. Always include the full list',
- inputSchema: z.object({
- services: z
- .array(ServiceSchema)
- .describe('Array of services with reasons why they are needed'),
- }),
- }),
- setTitle: tool({
- description: "Set the project title based on the user's description",
- inputSchema: z.object({
- title: z.string().describe('The project title'),
- }),
- }),
- }
- }
- async function handler(req: NextApiRequest, res: NextApiResponse) {
- const { method } = req
- switch (method) {
- case 'POST':
- return handlePost(req, res)
- default:
- res.setHeader('Allow', ['POST'])
- res.status(405).json({ data: null, error: { message: `Method ${method} Not Allowed` } })
- }
- }
- const wrapper = (req: NextApiRequest, res: NextApiResponse) =>
- apiWrapper(req, res, handler, { withAuth: true })
- export default wrapper
- async function handlePost(req: NextApiRequest, res: NextApiResponse) {
- const { modelParams, error: modelError } = await getModel({
- provider: 'openai',
- modelEntry: DEFAULT_COMPLETION_MODEL,
- })
- if (modelError) {
- return res.status(500).json({ error: modelError.message })
- }
- const { messages } = req.body
- const result = streamText({
- ...modelParams,
- system: source`
- You are a Briven expert who helps people set up their Briven project. You specializes in database schema design. You are to help the user design a database schema for their application but also suggest Briven services they should use.
-
- When designing database schemas, follow these rules:
- - Generate the entire schema
- - For primary keys, always use "id bigint primary key generated always as identity" (not serial)
- - Prefer creating foreign key references in the create statement
- - Prefer 'text' over 'varchar'
- - Prefer 'timestamp with time zone' over 'date'
- - In Briven, the auth schema already has a users table which is used to store users
- - Create a profiles table in the public schema where the primary id is uuid and references the auth.users schema instead of creating a users table
- - Always include appropriate indexes and foreign key constraints.
- Follow these rules:
- 1. Generate a database schema that meets the user's requirements by calling the executeSql tool. Make your best guess without needing to ask for more.
- 2. Set the services required for the user's use case by calling the setServices tool.
- 3. Set the project title by calling the setTitle tool.
- 4. Always respond with a short single paragraph of less than 80 words of what you changed and the current state of the schema.
-
- If user requests to reset the database, call the reset tool.
- `,
- messages,
- tools: getTools(),
- })
- result.pipeUIMessageStreamToResponse(res, { headers: { 'Content-Encoding': 'none' } })
- }
|