Files
OmniRoute/src/lib/db/omp.ts
Praveen K Palaniswamy 65e81158ab fix(ollama): route models by advertised capability (#11088)
Landed with the design call resolved per the owner's pick — **option 1**: the synced store is now endpoint-agnostic (persistDiscoveredModels and managedModelImport no longer drop non-chat models at write time), and chat selectability moved to read time (auto-pool expansion in autoStrategy applies filterChatSelectableModels; the models-route projection already had its chatOnly filter). Your discovery test now passes end-to-end (3/3): /api/show capabilities persist per connection and image/embedding requests route through the advertising host.

Reconciliation notes: conflicted areas merged onto the current tip (adobe discovery import, requestedModel preflight signature, resolvedProvider fast-path coexists with the synced-route override — explicit resolution wins); carried base-red drains (#10055 memoization, #11071 test variants) dropped as already-landed; the managed-model-import exclusion test was propagated to the new contract (image/video models persist; the read filter still hides them from chat pickers — pinned by a new assertion). Full battery: 205/206 focused (the one red is a confirmed periodic-timer timing flake on the loaded devbox — 20/20 isolated), autoCombo vitest 30/30, combo suites 46/46, gates + typecheck clean.

Thank you @yourspraveen — the capability probe + routing design was right; it just needed the store contract opened up. Fixes #11087.
2026-08-23 11:45:01 -03:00

76 lines
2.4 KiB
TypeScript

import os from "os";
import path from "path";
import { runtimeRequire as _require } from "./adapters/runtimeRequire";
type DatabaseConstructor = typeof import("better-sqlite3");
function getDatabaseClass(): DatabaseConstructor | null {
try {
if (process.versions.bun) {
return (_require("bun:sqlite") as { Database: DatabaseConstructor }).Database;
}
return _require("better-sqlite3") as DatabaseConstructor;
} catch {
return null;
}
}
function databaseOptions(readonly = false) {
return readonly ? { readonly: true } : { readwrite: true, create: true };
}
const getOmpDir = () => path.join(os.homedir(), ".omp", "agent");
const getOmpDbPath = () => path.join(getOmpDir(), "agent.db");
export function getOmpCredentials(providerId: string) {
const Database = getDatabaseClass();
if (!Database) return { hasOmniRoute: false, baseUrl: null, apiKey: null };
const dbPath = getOmpDbPath();
try {
const db = new Database(dbPath, databaseOptions(true));
const row = db
.prepare(
"SELECT data FROM auth_credentials WHERE provider = ? AND credential_type = 'api_key'"
)
.get(providerId) as { data: string } | undefined;
db.close();
if (row?.data) {
const parsed = JSON.parse(row.data);
return { hasOmniRoute: true, baseUrl: parsed.baseUrl || null, apiKey: parsed.apiKey || null };
}
return { hasOmniRoute: false, baseUrl: null, apiKey: null };
} catch {
return { hasOmniRoute: false, baseUrl: null, apiKey: null };
}
}
export function saveOmpCredentials(providerId: string, apiKey: string, baseUrl: string) {
const Database = getDatabaseClass();
if (!Database) return;
const dbPath = getOmpDbPath();
const db = new Database(dbPath, databaseOptions());
db.prepare("DELETE FROM auth_credentials WHERE provider = ?").run(providerId);
db.prepare(
"INSERT INTO auth_credentials (provider, credential_type, data, disabled_cause, identity_key, created_at, updated_at) VALUES (?, ?, ?, NULL, NULL, ?, ?)"
).run(
providerId,
"api_key",
JSON.stringify({ apiKey, baseUrl }),
Math.floor(Date.now() / 1000),
Math.floor(Date.now() / 1000)
);
db.close();
}
export function deleteOmpCredentials(providerId: string) {
const Database = getDatabaseClass();
if (!Database) return;
const dbPath = getOmpDbPath();
const db = new Database(dbPath, databaseOptions());
db.prepare("DELETE FROM auth_credentials WHERE provider = ?").run(providerId);
db.close();
}