mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-01 21:02:12 +03:00
240 lines
7.4 KiB
TypeScript
240 lines
7.4 KiB
TypeScript
/**
|
|
* db/models.js — Model aliases, MITM aliases, and custom models.
|
|
*/
|
|
|
|
import { getDbInstance } from "./core";
|
|
import { backupDbFile } from "./backup";
|
|
|
|
type JsonRecord = Record<string, unknown>;
|
|
|
|
function asRecord(value: unknown): JsonRecord {
|
|
return value && typeof value === "object" && !Array.isArray(value) ? (value as JsonRecord) : {};
|
|
}
|
|
|
|
function getKeyValue(row: unknown): { key: string | null; value: string | null } {
|
|
const record = asRecord(row);
|
|
return {
|
|
key: typeof record.key === "string" ? record.key : null,
|
|
value: typeof record.value === "string" ? record.value : null,
|
|
};
|
|
}
|
|
|
|
// ──────────────── Model Aliases ────────────────
|
|
|
|
export async function getModelAliases() {
|
|
const db = getDbInstance();
|
|
const rows = db
|
|
.prepare("SELECT key, value FROM key_value WHERE namespace = 'modelAliases'")
|
|
.all();
|
|
const result: Record<string, unknown> = {};
|
|
for (const row of rows) {
|
|
const { key, value } = getKeyValue(row);
|
|
if (!key || value === null) continue;
|
|
result[key] = JSON.parse(value);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
export async function setModelAlias(alias, model) {
|
|
const db = getDbInstance();
|
|
db.prepare(
|
|
"INSERT OR REPLACE INTO key_value (namespace, key, value) VALUES ('modelAliases', ?, ?)"
|
|
).run(alias, JSON.stringify(model));
|
|
backupDbFile("pre-write");
|
|
}
|
|
|
|
export async function deleteModelAlias(alias) {
|
|
const db = getDbInstance();
|
|
db.prepare("DELETE FROM key_value WHERE namespace = 'modelAliases' AND key = ?").run(alias);
|
|
backupDbFile("pre-write");
|
|
}
|
|
|
|
// ──────────────── MITM Alias ────────────────
|
|
|
|
export async function getMitmAlias(toolName) {
|
|
const db = getDbInstance();
|
|
if (toolName) {
|
|
const row = db
|
|
.prepare("SELECT value FROM key_value WHERE namespace = 'mitmAlias' AND key = ?")
|
|
.get(toolName);
|
|
const value = getKeyValue(row).value;
|
|
return value ? JSON.parse(value) : {};
|
|
}
|
|
const rows = db.prepare("SELECT key, value FROM key_value WHERE namespace = 'mitmAlias'").all();
|
|
const result: Record<string, unknown> = {};
|
|
for (const row of rows) {
|
|
const { key, value } = getKeyValue(row);
|
|
if (!key || value === null) continue;
|
|
result[key] = JSON.parse(value);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
export async function setMitmAliasAll(toolName, mappings) {
|
|
const db = getDbInstance();
|
|
db.prepare(
|
|
"INSERT OR REPLACE INTO key_value (namespace, key, value) VALUES ('mitmAlias', ?, ?)"
|
|
).run(toolName, JSON.stringify(mappings || {}));
|
|
backupDbFile("pre-write");
|
|
}
|
|
|
|
// ──────────────── Custom Models ────────────────
|
|
|
|
export async function getCustomModels(providerId) {
|
|
const db = getDbInstance();
|
|
if (providerId) {
|
|
const row = db
|
|
.prepare("SELECT value FROM key_value WHERE namespace = 'customModels' AND key = ?")
|
|
.get(providerId);
|
|
const value = getKeyValue(row).value;
|
|
return value ? JSON.parse(value) : [];
|
|
}
|
|
const rows = db
|
|
.prepare("SELECT key, value FROM key_value WHERE namespace = 'customModels'")
|
|
.all();
|
|
const result: Record<string, unknown> = {};
|
|
for (const row of rows) {
|
|
const { key, value } = getKeyValue(row);
|
|
if (!key || value === null) continue;
|
|
result[key] = JSON.parse(value);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
export async function getAllCustomModels() {
|
|
const db = getDbInstance();
|
|
const rows = db
|
|
.prepare("SELECT key, value FROM key_value WHERE namespace = 'customModels'")
|
|
.all();
|
|
const result: Record<string, unknown> = {};
|
|
for (const row of rows) {
|
|
const { key, value } = getKeyValue(row);
|
|
if (!key || value === null) continue;
|
|
result[key] = JSON.parse(value);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
export async function addCustomModel(
|
|
providerId: string,
|
|
modelId: string,
|
|
modelName?: string,
|
|
source = "manual",
|
|
apiFormat: "chat-completions" | "responses" = "chat-completions",
|
|
supportedEndpoints: string[] = ["chat"]
|
|
) {
|
|
const db = getDbInstance();
|
|
const row = db
|
|
.prepare("SELECT value FROM key_value WHERE namespace = 'customModels' AND key = ?")
|
|
.get(providerId);
|
|
const value = getKeyValue(row).value;
|
|
const models = value ? JSON.parse(value) : [];
|
|
|
|
const exists = models.find((m) => m.id === modelId);
|
|
if (exists) return exists;
|
|
|
|
const model = {
|
|
id: modelId,
|
|
name: modelName || modelId,
|
|
source,
|
|
apiFormat,
|
|
supportedEndpoints,
|
|
};
|
|
models.push(model);
|
|
db.prepare(
|
|
"INSERT OR REPLACE INTO key_value (namespace, key, value) VALUES ('customModels', ?, ?)"
|
|
).run(providerId, JSON.stringify(models));
|
|
backupDbFile("pre-write");
|
|
return model;
|
|
}
|
|
|
|
export async function removeCustomModel(providerId, modelId) {
|
|
const db = getDbInstance();
|
|
const row = db
|
|
.prepare("SELECT value FROM key_value WHERE namespace = 'customModels' AND key = ?")
|
|
.get(providerId);
|
|
if (!row) return false;
|
|
|
|
const value = getKeyValue(row).value;
|
|
if (!value) return false;
|
|
const models = JSON.parse(value);
|
|
const before = models.length;
|
|
const filtered = models.filter((m) => m.id !== modelId);
|
|
|
|
if (filtered.length === before) return false;
|
|
|
|
if (filtered.length === 0) {
|
|
db.prepare("DELETE FROM key_value WHERE namespace = 'customModels' AND key = ?").run(
|
|
providerId
|
|
);
|
|
} else {
|
|
db.prepare("UPDATE key_value SET value = ? WHERE namespace = 'customModels' AND key = ?").run(
|
|
JSON.stringify(filtered),
|
|
providerId
|
|
);
|
|
}
|
|
|
|
backupDbFile("pre-write");
|
|
return true;
|
|
}
|
|
|
|
export async function updateCustomModel(providerId, modelId, updates = {}) {
|
|
const db = getDbInstance();
|
|
const row = db
|
|
.prepare("SELECT value FROM key_value WHERE namespace = 'customModels' AND key = ?")
|
|
.get(providerId);
|
|
if (!row) return null;
|
|
|
|
const value = getKeyValue(row).value;
|
|
if (!value) return null;
|
|
|
|
const models = JSON.parse(value);
|
|
const index = models.findIndex((m) => m.id === modelId);
|
|
if (index === -1) return null;
|
|
|
|
const current = models[index];
|
|
const next = {
|
|
...current,
|
|
...(updates.modelName !== undefined ? { name: updates.modelName || current.name } : {}),
|
|
...(updates.apiFormat !== undefined ? { apiFormat: updates.apiFormat } : {}),
|
|
...(updates.supportedEndpoints !== undefined
|
|
? { supportedEndpoints: updates.supportedEndpoints }
|
|
: {}),
|
|
...(updates.normalizeToolCallId !== undefined
|
|
? { normalizeToolCallId: Boolean(updates.normalizeToolCallId) }
|
|
: {}),
|
|
};
|
|
|
|
models[index] = next;
|
|
|
|
db.prepare("UPDATE key_value SET value = ? WHERE namespace = 'customModels' AND key = ?").run(
|
|
JSON.stringify(models),
|
|
providerId
|
|
);
|
|
|
|
backupDbFile("pre-write");
|
|
return next;
|
|
}
|
|
|
|
/**
|
|
* Whether the given provider/model has "normalize tool call id" (9-char Mistral-style) enabled.
|
|
* Only custom models can have this set; returns false for built-in models.
|
|
*/
|
|
export function getModelNormalizeToolCallId(providerId: string, modelId: string): boolean {
|
|
const db = getDbInstance();
|
|
const row = db
|
|
.prepare("SELECT value FROM key_value WHERE namespace = 'customModels' AND key = ?")
|
|
.get(providerId);
|
|
const value = getKeyValue(row).value;
|
|
if (!value) return false;
|
|
let models: { id: string; normalizeToolCallId?: boolean }[];
|
|
try {
|
|
models = JSON.parse(value);
|
|
} catch {
|
|
return false;
|
|
}
|
|
if (!Array.isArray(models)) return false;
|
|
const m = models.find((x: { id: string }) => x.id === modelId);
|
|
return Boolean(m?.normalizeToolCallId);
|
|
}
|