Fix DB schema (#135)

This commit is contained in:
Will Chen
2025-05-12 16:12:36 -07:00
committed by GitHub
parent 477015b43d
commit e115074937
9 changed files with 67 additions and 58 deletions

View File

@@ -8,8 +8,9 @@ CREATE TABLE `language_model_providers` (
); );
--> statement-breakpoint --> statement-breakpoint
CREATE TABLE `language_models` ( CREATE TABLE `language_models` (
`id` text PRIMARY KEY NOT NULL, `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`name` text NOT NULL, `display_name` text NOT NULL,
`api_name` text NOT NULL,
`provider_id` text NOT NULL, `provider_id` text NOT NULL,
`description` text, `description` text,
`max_output_tokens` integer, `max_output_tokens` integer,

View File

@@ -1,7 +1,7 @@
{ {
"version": "6", "version": "6",
"dialect": "sqlite", "dialect": "sqlite",
"id": "f2ef6f83-09f5-4932-b7a0-4b205ba542ec", "id": "424973e5-a102-4b71-8d5d-6160f1609b8c",
"prevId": "ceedb797-6aa3-4a50-b42f-bc85ee08b3df", "prevId": "ceedb797-6aa3-4a50-b42f-bc85ee08b3df",
"tables": { "tables": {
"apps": { "apps": {
@@ -191,13 +191,20 @@
"columns": { "columns": {
"id": { "id": {
"name": "id", "name": "id",
"type": "text", "type": "integer",
"primaryKey": true, "primaryKey": true,
"notNull": true, "notNull": true,
"autoincrement": true
},
"display_name": {
"name": "display_name",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false "autoincrement": false
}, },
"name": { "api_name": {
"name": "name", "name": "api_name",
"type": "text", "type": "text",
"primaryKey": false, "primaryKey": false,
"notNull": true, "notNull": true,

View File

@@ -40,8 +40,8 @@
{ {
"idx": 5, "idx": 5,
"version": "6", "version": "6",
"when": 1747087890389, "when": 1747091036229,
"tag": "0005_hesitant_sister_grimm", "tag": "0005_superb_lady_mastermind",
"breakpoints": true "breakpoints": true
} }
] ]

View File

@@ -27,8 +27,8 @@ export function CreateCustomModelDialog({
onSuccess, onSuccess,
providerId, providerId,
}: CreateCustomModelDialogProps) { }: CreateCustomModelDialogProps) {
const [id, setId] = useState(""); const [apiName, setApiName] = useState("");
const [name, setName] = useState(""); const [displayName, setDisplayName] = useState("");
const [description, setDescription] = useState(""); const [description, setDescription] = useState("");
const [maxOutputTokens, setMaxOutputTokens] = useState<string>(""); const [maxOutputTokens, setMaxOutputTokens] = useState<string>("");
const [contextWindow, setContextWindow] = useState<string>(""); const [contextWindow, setContextWindow] = useState<string>("");
@@ -38,8 +38,8 @@ export function CreateCustomModelDialog({
const mutation = useMutation({ const mutation = useMutation({
mutationFn: async () => { mutationFn: async () => {
const params = { const params = {
id, apiName,
name, displayName,
providerId, providerId,
description: description || undefined, description: description || undefined,
maxOutputTokens: maxOutputTokens maxOutputTokens: maxOutputTokens
@@ -48,8 +48,9 @@ export function CreateCustomModelDialog({
contextWindow: contextWindow ? parseInt(contextWindow, 10) : undefined, contextWindow: contextWindow ? parseInt(contextWindow, 10) : undefined,
}; };
if (!params.id) throw new Error("Model ID is required"); if (!params.apiName) throw new Error("Model API name is required");
if (!params.name) throw new Error("Model Name is required"); if (!params.displayName)
throw new Error("Model display name is required");
if (maxOutputTokens && isNaN(params.maxOutputTokens ?? NaN)) if (maxOutputTokens && isNaN(params.maxOutputTokens ?? NaN))
throw new Error("Max Output Tokens must be a valid number"); throw new Error("Max Output Tokens must be a valid number");
if (contextWindow && isNaN(params.contextWindow ?? NaN)) if (contextWindow && isNaN(params.contextWindow ?? NaN))
@@ -69,8 +70,8 @@ export function CreateCustomModelDialog({
}); });
const resetForm = () => { const resetForm = () => {
setId(""); setApiName("");
setName(""); setDisplayName("");
setDescription(""); setDescription("");
setMaxOutputTokens(""); setMaxOutputTokens("");
setContextWindow(""); setContextWindow("");
@@ -105,9 +106,9 @@ export function CreateCustomModelDialog({
</Label> </Label>
<Input <Input
id="model-id" id="model-id"
value={id} value={apiName}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setId(e.target.value) setApiName(e.target.value)
} }
className="col-span-3" className="col-span-3"
placeholder="This must match the model expected by the API" placeholder="This must match the model expected by the API"
@@ -121,9 +122,9 @@ export function CreateCustomModelDialog({
</Label> </Label>
<Input <Input
id="model-name" id="model-name"
value={name} value={displayName}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
setName(e.target.value) setDisplayName(e.target.value)
} }
className="col-span-3" className="col-span-3"
placeholder="Human-friendly name for the model" placeholder="Human-friendly name for the model"

View File

@@ -46,7 +46,7 @@ export function ModelsSection({ providerId }: ModelsSectionProps) {
<div className="mt-4 space-y-3"> <div className="mt-4 space-y-3">
{models.map((model) => ( {models.map((model) => (
<div <div
key={model.name} key={model.apiName}
className="p-4 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm" className="p-4 bg-white dark:bg-gray-800 border border-gray-200 dark:border-gray-700 rounded-lg shadow-sm"
> >
<div className="flex justify-between items-center"> <div className="flex justify-between items-center">
@@ -56,7 +56,7 @@ export function ModelsSection({ providerId }: ModelsSectionProps) {
{/* Optional: Add an edit/delete button here later */} {/* Optional: Add an edit/delete button here later */}
</div> </div>
<p className="text-sm text-gray-500 dark:text-gray-400 italic"> <p className="text-sm text-gray-500 dark:text-gray-400 italic">
{model.name} {model.apiName}
</p> </p>
{model.description && ( {model.description && (
<p className="text-sm text-gray-600 dark:text-gray-300 mt-1"> <p className="text-sm text-gray-600 dark:text-gray-300 mt-1">

View File

@@ -82,8 +82,9 @@ export const language_model_providers = sqliteTable(
); );
export const language_models = sqliteTable("language_models", { export const language_models = sqliteTable("language_models", {
id: text("id").primaryKey(), id: integer("id").primaryKey({ autoIncrement: true }),
name: text("name").notNull(), displayName: text("display_name").notNull(),
apiName: text("api_name").notNull(),
provider_id: text("provider_id") provider_id: text("provider_id")
.notNull() .notNull()
.references(() => language_model_providers.id, { onDelete: "cascade" }), .references(() => language_model_providers.id, { onDelete: "cascade" }),

View File

@@ -87,8 +87,8 @@ export function registerLanguageModelHandlers() {
params: CreateCustomLanguageModelParams, params: CreateCustomLanguageModelParams,
): Promise<void> => { ): Promise<void> => {
const { const {
id, apiName,
name, displayName,
providerId, providerId,
description, description,
maxOutputTokens, maxOutputTokens,
@@ -96,11 +96,11 @@ export function registerLanguageModelHandlers() {
} = params; } = params;
// Validation // Validation
if (!id) { if (!apiName) {
throw new Error("Model ID is required"); throw new Error("Model API name is required");
} }
if (!name) { if (!displayName) {
throw new Error("Model name is required"); throw new Error("Model display name is required");
} }
if (!providerId) { if (!providerId) {
throw new Error("Provider ID is required"); throw new Error("Provider ID is required");
@@ -117,21 +117,10 @@ export function registerLanguageModelHandlers() {
throw new Error(`Provider with ID "${providerId}" not found`); throw new Error(`Provider with ID "${providerId}" not found`);
} }
// Check if model ID already exists
const existingModel = db
.select()
.from(languageModelsSchema)
.where(eq(languageModelsSchema.id, id))
.get();
if (existingModel) {
throw new Error(`A model with ID "${id}" already exists`);
}
// Insert the new model // Insert the new model
await db.insert(languageModelsSchema).values({ await db.insert(languageModelsSchema).values({
id, displayName,
name, apiName,
provider_id: providerId, provider_id: providerId,
description: description || null, description: description || null,
max_output_tokens: maxOutputTokens || null, max_output_tokens: maxOutputTokens || null,

View File

@@ -144,16 +144,26 @@ export interface LanguageModelProvider {
type: "custom" | "local" | "cloud"; type: "custom" | "local" | "cloud";
} }
export interface LanguageModel { export type LanguageModel =
id: string; | {
name: string; id: number;
apiName: string;
displayName: string; displayName: string;
description: string; description: string;
tag?: string; tag?: string;
maxOutputTokens?: number; maxOutputTokens?: number;
contextWindow?: number; contextWindow?: number;
type: "local" | "cloud" | "custom"; type: "custom";
} }
| {
apiName: string;
displayName: string;
description: string;
tag?: string;
maxOutputTokens?: number;
contextWindow?: number;
type: "local" | "cloud";
};
export interface CreateCustomLanguageModelProviderParams { export interface CreateCustomLanguageModelProviderParams {
id: string; id: string;
@@ -163,8 +173,8 @@ export interface CreateCustomLanguageModelProviderParams {
} }
export interface CreateCustomLanguageModelParams { export interface CreateCustomLanguageModelParams {
id: string; apiName: string;
name: string; displayName: string;
providerId: string; providerId: string;
description?: string; description?: string;
maxOutputTokens?: number; maxOutputTokens?: number;

View File

@@ -157,7 +157,7 @@ export async function getLanguageModels(obj: {
const models = MODEL_OPTIONS[providerId as RegularModelProvider] || []; const models = MODEL_OPTIONS[providerId as RegularModelProvider] || [];
return models.map((model) => ({ return models.map((model) => ({
...model, ...model,
id: model.name, apiName: model.name,
type: "cloud", type: "cloud",
})); }));
} else { } else {
@@ -174,7 +174,8 @@ export async function getLanguageModels(obj: {
.select({ .select({
id: languageModelsSchema.id, id: languageModelsSchema.id,
// Map DB columns to LanguageModel fields // Map DB columns to LanguageModel fields
name: languageModelsSchema.name, displayName: languageModelsSchema.displayName,
apiName: languageModelsSchema.apiName,
// No display_name in DB, use name instead // No display_name in DB, use name instead
description: languageModelsSchema.description, description: languageModelsSchema.description,
// No tag in DB // No tag in DB
@@ -186,7 +187,6 @@ export async function getLanguageModels(obj: {
return customModelsDb.map((model) => ({ return customModelsDb.map((model) => ({
...model, ...model,
displayName: model.name, // Use name as displayName for custom models
// Ensure possibly null fields are handled, provide defaults or undefined if needed // Ensure possibly null fields are handled, provide defaults or undefined if needed
description: model.description ?? "", description: model.description ?? "",
tag: undefined, // No tag for custom models from DB tag: undefined, // No tag for custom models from DB