refactor: Decouple model from provider

This commit is contained in:
2026-07-09 19:02:42 +05:30
parent acd62bdb65
commit 053748564f
5 changed files with 45 additions and 17 deletions

View File

@@ -31,6 +31,7 @@ export default function ConfigPage() {
const [editName, setEditName] = useState("");
const [editProvider, setEditProvider] = useState("google-genai");
const [editKey, setEditKey] = useState("");
const [editModel, setEditModel] = useState("gemini-2.5-flash");
const [editIsActive, setEditIsActive] = useState(false);
useEffect(() => {
@@ -38,6 +39,7 @@ export default function ConfigPage() {
setEditName("");
setEditProvider("google-genai");
setEditKey("");
setEditModel("gemini-2.5-flash");
setEditIsActive(false);
} else {
const inst = instances.find((i) => i.id === selectedInstanceId);
@@ -45,6 +47,7 @@ export default function ConfigPage() {
setEditName(inst.name);
setEditProvider(inst.providerName);
setEditKey("");
setEditModel(inst.modelName || "gemini-2.5-flash");
setEditIsActive(inst.isActive);
}
}
@@ -104,13 +107,13 @@ export default function ConfigPage() {
setLoading(false);
return;
}
const created = await createProviderInstance(editName, editProvider, editKey);
const created = await createProviderInstance(editName, editProvider, editKey, editModel || undefined);
if (editIsActive) {
await setActiveProviderInstance(created.id);
}
setSelectedInstanceId(created.id);
} else {
await updateProviderInstance(selectedInstanceId, editName, editProvider, editKey || undefined);
await updateProviderInstance(selectedInstanceId, editName, editProvider, editKey || undefined, editModel || undefined);
if (editIsActive) {
await setActiveProviderInstance(selectedInstanceId);
}
@@ -251,6 +254,17 @@ export default function ConfigPage() {
/>
</div>
<div className="form-group">
<label htmlFor="formModel">Model Name</label>
<input
id="formModel"
type="text"
value={editModel}
onChange={(e) => setEditModel(e.target.value)}
placeholder="e.g. gemini-2.5-flash, gemini-2.5-pro"
/>
</div>
<div className="form-group checkbox-group">
<input
id="formActive"

View File

@@ -242,8 +242,9 @@ export async function createProviderInstance(
name: string,
providerName: string,
apiKey: string,
modelName?: string,
): Promise<LLMProviderInstance> {
return ProviderManager.create(name, providerName, apiKey);
return ProviderManager.create(name, providerName, apiKey, modelName);
}
export async function deleteProviderInstance(id: string): Promise<void> {
@@ -259,8 +260,9 @@ export async function updateProviderInstance(
name: string,
providerName: string,
apiKey?: string,
modelName?: string,
): Promise<void> {
ProviderManager.update(id, name, providerName, apiKey);
ProviderManager.update(id, name, providerName, apiKey, modelName);
}
export async function getProviderMappings(): Promise<Record<string, string>> {

View File

@@ -19,9 +19,16 @@ function getSettingsDb() {
name TEXT NOT NULL,
providerName TEXT NOT NULL,
apiKey TEXT NOT NULL,
isActive INTEGER NOT NULL DEFAULT 0
isActive INTEGER NOT NULL DEFAULT 0,
modelName TEXT
)
`).run();
try {
db.prepare(`ALTER TABLE provider_instances ADD COLUMN modelName TEXT`).run();
} catch {
// ignore
}
return db;
}
@@ -36,6 +43,7 @@ export class ProviderManager {
providerName: string;
apiKey: string;
isActive: number;
modelName?: string;
}[];
return rows.map((r) => ({
id: r.id,
@@ -43,13 +51,14 @@ export class ProviderManager {
providerName: r.providerName,
apiKey: r.apiKey,
isActive: r.isActive === 1,
modelName: r.modelName || undefined,
}));
} finally {
db.close();
}
}
static create(name: string, providerName: string, apiKey: string): LLMProviderInstance {
static create(name: string, providerName: string, apiKey: string, modelName?: string): LLMProviderInstance {
const db = getSettingsDb();
try {
const id = "provider-" + Date.now();
@@ -57,11 +66,11 @@ export class ProviderManager {
const isActive = activeCount.count === 0 ? 1 : 0;
db.prepare(`
INSERT INTO provider_instances (id, name, providerName, apiKey, isActive)
VALUES (?, ?, ?, ?, ?)
`).run(id, name, providerName, apiKey, isActive);
INSERT INTO provider_instances (id, name, providerName, apiKey, isActive, modelName)
VALUES (?, ?, ?, ?, ?, ?)
`).run(id, name, providerName, apiKey, isActive, modelName || null);
return { id, name, providerName, apiKey, isActive: isActive === 1 };
return { id, name, providerName, apiKey, isActive: isActive === 1, modelName };
} finally {
db.close();
}
@@ -94,21 +103,21 @@ export class ProviderManager {
}
}
static update(id: string, name: string, providerName: string, apiKey?: string): void {
static update(id: string, name: string, providerName: string, apiKey?: string, modelName?: string): void {
const db = getSettingsDb();
try {
if (apiKey && apiKey.trim()) {
db.prepare(`
UPDATE provider_instances
SET name = ?, providerName = ?, apiKey = ?
SET name = ?, providerName = ?, apiKey = ?, modelName = ?
WHERE id = ?
`).run(name, providerName, apiKey, id);
`).run(name, providerName, apiKey, modelName || null, id);
} else {
db.prepare(`
UPDATE provider_instances
SET name = ?, providerName = ?
SET name = ?, providerName = ?, modelName = ?
WHERE id = ?
`).run(name, providerName, id);
`).run(name, providerName, modelName || null, id);
}
} finally {
db.close();
@@ -124,6 +133,7 @@ export class ProviderManager {
providerName: string;
apiKey: string;
isActive: number;
modelName?: string;
} | undefined;
if (!row) return null;
return {
@@ -132,6 +142,7 @@ export class ProviderManager {
providerName: row.providerName,
apiKey: row.apiKey,
isActive: true,
modelName: row.modelName || undefined,
};
} finally {
db.close();

View File

@@ -43,4 +43,5 @@ export interface LLMProviderInstance {
providerName: string;
apiKey: string;
isActive: boolean;
modelName?: string;
}

View File

@@ -8,14 +8,14 @@ export class GeminiProvider implements ILLMProvider {
private model: ChatGoogleGenerativeAI;
lastCalls: LLMCallRecord[] = [];
constructor(apiKey?: string) {
constructor(apiKey?: string, modelName?: string) {
const key = apiKey || llmConfig.GOOGLE_API_KEY;
if (!key) {
throw new Error("GOOGLE_API_KEY is required to initialize GeminiProvider");
}
this.model = new ChatGoogleGenerativeAI({
apiKey: key,
model: "gemini-2.5-flash",
model: modelName || "gemini-2.5-flash",
});
}