page.tsx82 lines · main
1import { apiJson } from '../../../../../../lib/api';
2import { AiFunctionForm } from './ai-function-form';
3import { AiSubnav } from '../ai-subnav';
4
5interface ColumnDef {
6 sqlType: string;
7 nullable: boolean;
8 primaryKey: boolean;
9 unique: boolean;
10 default?: string;
11 references?: { table: string; column: string };
12}
13
14interface TableDef {
15 columns: Record<string, ColumnDef>;
16 indexes: Array<{ columns: string[]; unique: boolean }>;
17}
18
19interface SchemaSnapshot {
20 version: 1;
21 tables: Record<string, TableDef>;
22}
23
24interface CurrentSchemaResponse {
25 deploymentId: string | null;
26 snapshot: SchemaSnapshot | null;
27}
28
29export const metadata = { title: 'ai function' };
30export const dynamic = 'force-dynamic';
31
32/**
33 * Render the JSON snapshot as a compact TypeScript-flavoured summary the
34 * model can read. The dashboard SSRs this so the client form receives
35 * the already-formatted string and doesn't need a second round-trip.
36 */
37function snapshotToContext(snapshot: SchemaSnapshot): string {
38 const lines: string[] = [];
39 for (const [tableName, table] of Object.entries(snapshot.tables)) {
40 const cols = Object.entries(table.columns)
41 .map(([name, col]) => {
42 const parts = [`${name}: ${col.sqlType}`];
43 if (col.primaryKey) parts.push('PK');
44 if (col.unique) parts.push('UNIQUE');
45 if (!col.nullable) parts.push('NOT NULL');
46 if (col.references) parts.push(`-> ${col.references.table}.${col.references.column}`);
47 return ` ${parts.join(' ')}`;
48 })
49 .join('\n');
50 lines.push(`table ${tableName} {\n${cols}\n}`);
51 }
52 return lines.join('\n\n');
53}
54
55export default async function AiFunctionPage({ params }: { params: Promise<{ id: string }> }) {
56 const { id } = await params;
57 const current = await apiJson<CurrentSchemaResponse>(`/v1/projects/${id}/schema/current`).catch(
58 () => null,
59 );
60 const schemaContext = current?.snapshot ? snapshotToContext(current.snapshot) : null;
61
62 return (
63 <section className="flex flex-col gap-6">
64 <AiSubnav projectId={id} />
65 <header>
66 <h1 className="font-mono text-xl tracking-tight">ai function</h1>
67 <p className="mt-1 font-mono text-sm text-[var(--color-text-muted)]">
68 describe what a function should do. briven&apos;s AI assistant returns a draft{' '}
69 <code>briven/functions/&lt;name&gt;.ts</code> file using your project&apos;s current
70 schema as context.
71 </p>
72 <p className="mt-2 font-mono text-xs text-[var(--color-text-subtle)]">
73 your prompt + (optional) schema context are sent to a self-hosted Qwen 2.5-coder model on
74 briven infrastructure — not to any third-party AI provider. prompts and responses are not
75 logged.
76 </p>
77 </header>
78
79 <AiFunctionForm projectId={id} schemaContext={schemaContext} />
80 </section>
81 );
82}