@houtini/lm 2.3.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +202 -114
- package/dist/index.js +562 -49
- package/dist/index.js.map +1 -1
- package/dist/model-cache.d.ts +87 -0
- package/dist/model-cache.js +516 -0
- package/dist/model-cache.js.map +1 -0
- package/package.json +4 -2
- package/server.json +44 -44
|
@@ -0,0 +1,516 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite-backed model profile cache.
|
|
3
|
+
*
|
|
4
|
+
* On startup, houtini-lm fetches available models from the LLM server and
|
|
5
|
+
* looks up each one on HuggingFace's free API. The results are cached in a
|
|
6
|
+
* local SQLite database so subsequent startups are instant (no network).
|
|
7
|
+
*
|
|
8
|
+
* Uses sql.js (pure WASM) — zero native deps, works everywhere.
|
|
9
|
+
*/
|
|
10
|
+
import initSqlJs from 'sql.js';
|
|
11
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
import { homedir } from 'node:os';
|
|
14
|
+
const PROMPT_HINTS = [
|
|
15
|
+
{
|
|
16
|
+
pattern: /glm[- ]?4/i,
|
|
17
|
+
hints: {
|
|
18
|
+
codeTemp: 0.1,
|
|
19
|
+
chatTemp: 0.3,
|
|
20
|
+
outputConstraint: 'Respond with ONLY the requested output. No step-by-step reasoning. No numbered analysis. No preamble. Go straight to the answer.',
|
|
21
|
+
emitsThinkBlocks: true,
|
|
22
|
+
bestTaskTypes: ['chat', 'analysis'],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
pattern: /qwen3.*coder|qwen.*coder/i,
|
|
27
|
+
hints: {
|
|
28
|
+
codeTemp: 0.1,
|
|
29
|
+
chatTemp: 0.3,
|
|
30
|
+
outputConstraint: 'Be direct. Output only what was asked for.',
|
|
31
|
+
emitsThinkBlocks: true,
|
|
32
|
+
bestTaskTypes: ['code'],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
pattern: /qwen3(?!.*coder)(?!.*vl)/i,
|
|
37
|
+
hints: {
|
|
38
|
+
codeTemp: 0.2,
|
|
39
|
+
chatTemp: 0.3,
|
|
40
|
+
outputConstraint: 'Be direct. Output only what was asked for.',
|
|
41
|
+
emitsThinkBlocks: true,
|
|
42
|
+
bestTaskTypes: ['chat', 'analysis', 'code'],
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
pattern: /llama[- ]?3/i,
|
|
47
|
+
hints: {
|
|
48
|
+
codeTemp: 0.2,
|
|
49
|
+
chatTemp: 0.4,
|
|
50
|
+
outputConstraint: '',
|
|
51
|
+
emitsThinkBlocks: false,
|
|
52
|
+
bestTaskTypes: ['chat', 'code', 'analysis'],
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
pattern: /nemotron/i,
|
|
57
|
+
hints: {
|
|
58
|
+
codeTemp: 0.1,
|
|
59
|
+
chatTemp: 0.3,
|
|
60
|
+
outputConstraint: '',
|
|
61
|
+
emitsThinkBlocks: true,
|
|
62
|
+
bestTaskTypes: ['analysis', 'code'],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
pattern: /granite/i,
|
|
67
|
+
hints: {
|
|
68
|
+
codeTemp: 0.2,
|
|
69
|
+
chatTemp: 0.3,
|
|
70
|
+
outputConstraint: '',
|
|
71
|
+
emitsThinkBlocks: false,
|
|
72
|
+
bestTaskTypes: ['code', 'chat'],
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
pattern: /gpt[- ]?oss/i,
|
|
77
|
+
hints: {
|
|
78
|
+
codeTemp: 0.2,
|
|
79
|
+
chatTemp: 0.4,
|
|
80
|
+
outputConstraint: '',
|
|
81
|
+
emitsThinkBlocks: false,
|
|
82
|
+
bestTaskTypes: ['chat', 'code', 'analysis'],
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
pattern: /nomic.*embed|embed.*nomic/i,
|
|
87
|
+
hints: {
|
|
88
|
+
codeTemp: 0,
|
|
89
|
+
chatTemp: 0,
|
|
90
|
+
outputConstraint: '',
|
|
91
|
+
emitsThinkBlocks: false,
|
|
92
|
+
bestTaskTypes: ['embedding'],
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
];
|
|
96
|
+
/**
|
|
97
|
+
* Get prompt hints for a model by ID or architecture.
|
|
98
|
+
*/
|
|
99
|
+
export function getPromptHints(modelId, arch) {
|
|
100
|
+
for (const { pattern, hints } of PROMPT_HINTS) {
|
|
101
|
+
if (pattern.test(modelId))
|
|
102
|
+
return hints;
|
|
103
|
+
if (arch && pattern.test(arch))
|
|
104
|
+
return hints;
|
|
105
|
+
}
|
|
106
|
+
// Sensible defaults for unknown models
|
|
107
|
+
return {
|
|
108
|
+
codeTemp: 0.2,
|
|
109
|
+
chatTemp: 0.3,
|
|
110
|
+
outputConstraint: '',
|
|
111
|
+
emitsThinkBlocks: false,
|
|
112
|
+
bestTaskTypes: ['chat', 'code', 'analysis'],
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
// ── Constants ────────────────────────────────────────────────────────
|
|
116
|
+
const DB_DIR = join(homedir(), '.houtini-lm');
|
|
117
|
+
const DB_PATH = join(DB_DIR, 'model-cache.db');
|
|
118
|
+
const CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
119
|
+
const HF_TIMEOUT_MS = 8000;
|
|
120
|
+
// ── Database ─────────────────────────────────────────────────────────
|
|
121
|
+
let db = null;
|
|
122
|
+
export async function initDb() {
|
|
123
|
+
if (db)
|
|
124
|
+
return db;
|
|
125
|
+
const SQL = await initSqlJs();
|
|
126
|
+
// Load existing DB from disk if it exists
|
|
127
|
+
if (existsSync(DB_PATH)) {
|
|
128
|
+
try {
|
|
129
|
+
const buf = readFileSync(DB_PATH);
|
|
130
|
+
db = new SQL.Database(buf);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
// Corrupt DB — start fresh
|
|
134
|
+
db = new SQL.Database();
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
db = new SQL.Database();
|
|
139
|
+
}
|
|
140
|
+
// Create table if not exists
|
|
141
|
+
db.run(`
|
|
142
|
+
CREATE TABLE IF NOT EXISTS model_profiles (
|
|
143
|
+
model_id TEXT PRIMARY KEY,
|
|
144
|
+
hf_id TEXT,
|
|
145
|
+
pipeline_tag TEXT,
|
|
146
|
+
architectures TEXT,
|
|
147
|
+
license TEXT,
|
|
148
|
+
downloads INTEGER,
|
|
149
|
+
likes INTEGER,
|
|
150
|
+
library_name TEXT,
|
|
151
|
+
family TEXT,
|
|
152
|
+
description TEXT,
|
|
153
|
+
strengths TEXT,
|
|
154
|
+
weaknesses TEXT,
|
|
155
|
+
best_for TEXT,
|
|
156
|
+
fetched_at INTEGER NOT NULL,
|
|
157
|
+
source TEXT NOT NULL DEFAULT 'huggingface'
|
|
158
|
+
)
|
|
159
|
+
`);
|
|
160
|
+
return db;
|
|
161
|
+
}
|
|
162
|
+
function saveDb() {
|
|
163
|
+
if (!db)
|
|
164
|
+
return;
|
|
165
|
+
try {
|
|
166
|
+
mkdirSync(DB_DIR, { recursive: true });
|
|
167
|
+
const data = db.export();
|
|
168
|
+
writeFileSync(DB_PATH, Buffer.from(data));
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
process.stderr.write(`[houtini-lm] Failed to save model cache: ${err}\n`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// ── Cache operations ─────────────────────────────────────────────────
|
|
175
|
+
export async function getCachedProfile(modelId) {
|
|
176
|
+
const database = await initDb();
|
|
177
|
+
const stmt = database.prepare('SELECT * FROM model_profiles WHERE model_id = ?');
|
|
178
|
+
stmt.bind([modelId]);
|
|
179
|
+
if (stmt.step()) {
|
|
180
|
+
const row = stmt.getAsObject();
|
|
181
|
+
stmt.free();
|
|
182
|
+
return {
|
|
183
|
+
modelId: row.model_id,
|
|
184
|
+
hfId: row.hf_id,
|
|
185
|
+
pipelineTag: row.pipeline_tag,
|
|
186
|
+
architectures: row.architectures,
|
|
187
|
+
license: row.license,
|
|
188
|
+
downloads: row.downloads,
|
|
189
|
+
likes: row.likes,
|
|
190
|
+
libraryName: row.library_name,
|
|
191
|
+
family: row.family,
|
|
192
|
+
description: row.description,
|
|
193
|
+
strengths: row.strengths,
|
|
194
|
+
weaknesses: row.weaknesses,
|
|
195
|
+
bestFor: row.best_for,
|
|
196
|
+
fetchedAt: row.fetched_at,
|
|
197
|
+
source: row.source,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
stmt.free();
|
|
201
|
+
return null;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Insert or update a profile in the DB. Saves to disk immediately by default.
|
|
205
|
+
* Pass skipSave=true during batch operations, then call flushDb() when done.
|
|
206
|
+
*/
|
|
207
|
+
export async function upsertProfile(profile, skipSave = false) {
|
|
208
|
+
const database = await initDb();
|
|
209
|
+
database.run(`INSERT OR REPLACE INTO model_profiles
|
|
210
|
+
(model_id, hf_id, pipeline_tag, architectures, license, downloads, likes, library_name,
|
|
211
|
+
family, description, strengths, weaknesses, best_for, fetched_at, source)
|
|
212
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
213
|
+
profile.modelId,
|
|
214
|
+
profile.hfId,
|
|
215
|
+
profile.pipelineTag,
|
|
216
|
+
profile.architectures,
|
|
217
|
+
profile.license,
|
|
218
|
+
profile.downloads,
|
|
219
|
+
profile.likes,
|
|
220
|
+
profile.libraryName,
|
|
221
|
+
profile.family,
|
|
222
|
+
profile.description,
|
|
223
|
+
profile.strengths,
|
|
224
|
+
profile.weaknesses,
|
|
225
|
+
profile.bestFor,
|
|
226
|
+
profile.fetchedAt,
|
|
227
|
+
profile.source,
|
|
228
|
+
]);
|
|
229
|
+
if (!skipSave)
|
|
230
|
+
saveDb();
|
|
231
|
+
}
|
|
232
|
+
/** Flush DB to disk. Call after batch upsertProfile(…, true) operations. */
|
|
233
|
+
export function flushDb() {
|
|
234
|
+
saveDb();
|
|
235
|
+
}
|
|
236
|
+
export function isCacheStale(profile) {
|
|
237
|
+
return Date.now() - profile.fetchedAt > CACHE_TTL_MS;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Convert a cached profile to the ModelProfile format used by the rest of the app.
|
|
241
|
+
*/
|
|
242
|
+
export function toModelProfile(cached) {
|
|
243
|
+
if (!cached.family || !cached.description)
|
|
244
|
+
return null;
|
|
245
|
+
return {
|
|
246
|
+
family: cached.family,
|
|
247
|
+
description: cached.description,
|
|
248
|
+
strengths: cached.strengths ? JSON.parse(cached.strengths) : [],
|
|
249
|
+
weaknesses: cached.weaknesses ? JSON.parse(cached.weaknesses) : [],
|
|
250
|
+
bestFor: cached.bestFor ? JSON.parse(cached.bestFor) : [],
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
async function fetchHF(url) {
|
|
254
|
+
const controller = new AbortController();
|
|
255
|
+
const timer = setTimeout(() => controller.abort(), HF_TIMEOUT_MS);
|
|
256
|
+
try {
|
|
257
|
+
return await fetch(url, { headers: { Accept: 'application/json' }, signal: controller.signal });
|
|
258
|
+
}
|
|
259
|
+
finally {
|
|
260
|
+
clearTimeout(timer);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
/**
|
|
264
|
+
* Try to find a model on HuggingFace given a local model ID and optional publisher.
|
|
265
|
+
* Returns the HF card or null.
|
|
266
|
+
*/
|
|
267
|
+
async function lookupHF(modelId, publisher) {
|
|
268
|
+
const candidates = [];
|
|
269
|
+
if (modelId.includes('/')) {
|
|
270
|
+
candidates.push(modelId);
|
|
271
|
+
}
|
|
272
|
+
if (publisher && !modelId.includes('/')) {
|
|
273
|
+
candidates.push(`${publisher}/${modelId}`);
|
|
274
|
+
}
|
|
275
|
+
for (const hfId of candidates) {
|
|
276
|
+
try {
|
|
277
|
+
const res = await fetchHF(`https://huggingface.co/api/models/${hfId}`);
|
|
278
|
+
if (res.ok)
|
|
279
|
+
return (await res.json());
|
|
280
|
+
}
|
|
281
|
+
catch {
|
|
282
|
+
// skip
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
// ── Auto-profile generation ──────────────────────────────────────────
|
|
288
|
+
// When HF gives us metadata but we don't have a hardcoded profile,
|
|
289
|
+
// generate a reasonable one from the available data.
|
|
290
|
+
function inferProfileFromHF(card, modelId) {
|
|
291
|
+
const tag = card.pipeline_tag || '';
|
|
292
|
+
const tags = card.tags || [];
|
|
293
|
+
const arch = card.config?.architectures?.[0] || '';
|
|
294
|
+
// Extract org/family from HF ID
|
|
295
|
+
const parts = card.id.split('/');
|
|
296
|
+
const org = parts.length > 1 ? parts[0] : '';
|
|
297
|
+
const modelName = parts.length > 1 ? parts[1] : parts[0];
|
|
298
|
+
// Infer family name from model ID
|
|
299
|
+
const family = inferFamily(modelName, org);
|
|
300
|
+
// Infer description
|
|
301
|
+
let description = `${org ? org + "'s " : ''}${family} model.`;
|
|
302
|
+
if (tag === 'text-generation')
|
|
303
|
+
description += ' Text generation / chat model.';
|
|
304
|
+
else if (tag === 'image-text-to-text')
|
|
305
|
+
description += ' Vision-language model — handles text and image inputs.';
|
|
306
|
+
else if (tag === 'feature-extraction' || tag === 'sentence-similarity')
|
|
307
|
+
description += ' Embedding model for semantic search.';
|
|
308
|
+
if (card.cardData?.license)
|
|
309
|
+
description += ` License: ${card.cardData.license}.`;
|
|
310
|
+
// Infer strengths from tags
|
|
311
|
+
const strengths = [];
|
|
312
|
+
const weaknesses = [];
|
|
313
|
+
const bestFor = [];
|
|
314
|
+
if (tag === 'text-generation') {
|
|
315
|
+
strengths.push('text generation', 'instruction following');
|
|
316
|
+
bestFor.push('general delegation', 'Q&A');
|
|
317
|
+
}
|
|
318
|
+
if (tag === 'image-text-to-text') {
|
|
319
|
+
strengths.push('image understanding', 'visual Q&A');
|
|
320
|
+
bestFor.push('screenshot analysis', 'diagram interpretation');
|
|
321
|
+
}
|
|
322
|
+
if (tags.includes('code') || modelName.toLowerCase().includes('code')) {
|
|
323
|
+
strengths.push('code generation');
|
|
324
|
+
bestFor.push('code tasks');
|
|
325
|
+
}
|
|
326
|
+
if (tags.includes('math') || modelName.toLowerCase().includes('math')) {
|
|
327
|
+
strengths.push('mathematics', 'reasoning');
|
|
328
|
+
bestFor.push('math/science questions');
|
|
329
|
+
}
|
|
330
|
+
if (tags.includes('conversational')) {
|
|
331
|
+
strengths.push('conversation');
|
|
332
|
+
bestFor.push('chat', 'brainstorming');
|
|
333
|
+
}
|
|
334
|
+
// Default if nothing specific found
|
|
335
|
+
if (strengths.length === 0)
|
|
336
|
+
strengths.push('general reasoning');
|
|
337
|
+
if (bestFor.length === 0)
|
|
338
|
+
bestFor.push('general delegation');
|
|
339
|
+
return {
|
|
340
|
+
family,
|
|
341
|
+
description,
|
|
342
|
+
strengths: JSON.stringify(strengths),
|
|
343
|
+
weaknesses: JSON.stringify(weaknesses),
|
|
344
|
+
bestFor: JSON.stringify(bestFor),
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
function inferFamily(modelName, org) {
|
|
348
|
+
// Try to extract a clean family name from the model ID
|
|
349
|
+
// e.g. "glm-4.7-flash" -> "GLM-4", "qwen3-coder-30b" -> "Qwen3 Coder"
|
|
350
|
+
const lower = modelName.toLowerCase();
|
|
351
|
+
// Common patterns
|
|
352
|
+
const familyPatterns = [
|
|
353
|
+
[/^glm[- ]?(\d)/i, 'GLM-$1'],
|
|
354
|
+
[/^qwen(\d)[- ]?coder/i, 'Qwen$1 Coder'],
|
|
355
|
+
[/^qwen(\d)[- ]?vl/i, 'Qwen$1 VL'],
|
|
356
|
+
[/^qwen(\d)/i, 'Qwen$1'],
|
|
357
|
+
[/^llama[- ]?(\d)/i, 'LLaMA $1'],
|
|
358
|
+
[/^nemotron/i, 'Nemotron'],
|
|
359
|
+
[/^granite/i, 'Granite'],
|
|
360
|
+
[/^mistral/i, 'Mistral'],
|
|
361
|
+
[/^mixtral/i, 'Mixtral'],
|
|
362
|
+
[/^deepseek/i, 'DeepSeek'],
|
|
363
|
+
[/^phi[- ]?(\d)/i, 'Phi-$1'],
|
|
364
|
+
[/^gemma[- ]?(\d)/i, 'Gemma $1'],
|
|
365
|
+
[/^starcoder/i, 'StarCoder'],
|
|
366
|
+
[/^codestral/i, 'Codestral'],
|
|
367
|
+
[/^command[- ]?r/i, 'Command R'],
|
|
368
|
+
[/^internlm/i, 'InternLM'],
|
|
369
|
+
[/^yi[- ]?(\d)/i, 'Yi-$1'],
|
|
370
|
+
[/^nomic/i, 'Nomic'],
|
|
371
|
+
[/^gpt[- ]?oss/i, 'GPT-OSS'],
|
|
372
|
+
[/^minimax/i, 'MiniMax'],
|
|
373
|
+
[/^kimi/i, 'Kimi'],
|
|
374
|
+
];
|
|
375
|
+
for (const [pattern, replacement] of familyPatterns) {
|
|
376
|
+
if (pattern.test(lower)) {
|
|
377
|
+
return modelName.replace(pattern, replacement);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
// Fallback: use org + first meaningful part of name
|
|
381
|
+
const firstPart = modelName.split(/[-_ ]/)[0];
|
|
382
|
+
return org ? `${org}/${firstPart}` : firstPart;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Profile all models at startup. For each model:
|
|
386
|
+
* 1. Check SQLite cache — if fresh, skip
|
|
387
|
+
* 2. Look up on HuggingFace — if found, auto-generate profile and cache
|
|
388
|
+
* 3. If HF miss, cache as "inferred" with whatever metadata we have
|
|
389
|
+
*
|
|
390
|
+
* Runs in the background — never blocks server startup.
|
|
391
|
+
*/
|
|
392
|
+
export async function profileModelsAtStartup(models) {
|
|
393
|
+
const database = await initDb();
|
|
394
|
+
let profiledCount = 0;
|
|
395
|
+
let cachedCount = 0;
|
|
396
|
+
for (const model of models) {
|
|
397
|
+
try {
|
|
398
|
+
// Check cache
|
|
399
|
+
const cached = await getCachedProfile(model.id);
|
|
400
|
+
if (cached && !isCacheStale(cached)) {
|
|
401
|
+
cachedCount++;
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
// Look up on HuggingFace
|
|
405
|
+
const card = await lookupHF(model.id, model.publisher);
|
|
406
|
+
if (card) {
|
|
407
|
+
const inferred = inferProfileFromHF(card, model.id);
|
|
408
|
+
await upsertProfile({
|
|
409
|
+
modelId: model.id,
|
|
410
|
+
hfId: card.id,
|
|
411
|
+
pipelineTag: card.pipeline_tag || null,
|
|
412
|
+
architectures: card.config?.architectures ? JSON.stringify(card.config.architectures) : null,
|
|
413
|
+
license: card.cardData?.license || null,
|
|
414
|
+
downloads: card.downloads || null,
|
|
415
|
+
likes: card.likes || null,
|
|
416
|
+
libraryName: card.library_name || null,
|
|
417
|
+
family: inferred.family || null,
|
|
418
|
+
description: inferred.description || null,
|
|
419
|
+
strengths: inferred.strengths || null,
|
|
420
|
+
weaknesses: inferred.weaknesses || null,
|
|
421
|
+
bestFor: inferred.bestFor || null,
|
|
422
|
+
fetchedAt: Date.now(),
|
|
423
|
+
source: 'huggingface',
|
|
424
|
+
}, true);
|
|
425
|
+
profiledCount++;
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
// No HF match — cache a minimal profile so we don't retry
|
|
429
|
+
await upsertProfile({
|
|
430
|
+
modelId: model.id,
|
|
431
|
+
hfId: null,
|
|
432
|
+
pipelineTag: model.type || null,
|
|
433
|
+
architectures: model.arch ? JSON.stringify([model.arch]) : null,
|
|
434
|
+
license: null,
|
|
435
|
+
downloads: null,
|
|
436
|
+
likes: null,
|
|
437
|
+
libraryName: null,
|
|
438
|
+
family: inferFamily(model.id.split('/').pop() || model.id, model.publisher || ''),
|
|
439
|
+
description: `${model.publisher ? model.publisher + "'s " : ''}local model. No HuggingFace card found.`,
|
|
440
|
+
strengths: null,
|
|
441
|
+
weaknesses: null,
|
|
442
|
+
bestFor: null,
|
|
443
|
+
fetchedAt: Date.now(),
|
|
444
|
+
source: 'inferred',
|
|
445
|
+
}, true);
|
|
446
|
+
profiledCount++;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
catch (err) {
|
|
450
|
+
process.stderr.write(`[houtini-lm] Failed to profile ${model.id}: ${err}\n`);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
// Flush all changes to disk in one write
|
|
454
|
+
if (profiledCount > 0)
|
|
455
|
+
flushDb();
|
|
456
|
+
process.stderr.write(`[houtini-lm] Model cache: ${cachedCount} cached, ${profiledCount} profiled, ${models.length} total\n`);
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Get a profile for display — checks SQLite first, returns formatted enrichment line.
|
|
460
|
+
*/
|
|
461
|
+
export async function getHFEnrichmentLine(modelId) {
|
|
462
|
+
const cached = await getCachedProfile(modelId);
|
|
463
|
+
if (!cached || cached.source === 'inferred')
|
|
464
|
+
return '';
|
|
465
|
+
const parts = [];
|
|
466
|
+
if (cached.pipelineTag)
|
|
467
|
+
parts.push(`HF task: ${cached.pipelineTag}`);
|
|
468
|
+
if (cached.libraryName)
|
|
469
|
+
parts.push(`library: ${cached.libraryName}`);
|
|
470
|
+
if (cached.downloads)
|
|
471
|
+
parts.push(`${cached.downloads.toLocaleString()} downloads`);
|
|
472
|
+
if (cached.likes)
|
|
473
|
+
parts.push(`${cached.likes.toLocaleString()} likes`);
|
|
474
|
+
if (cached.license)
|
|
475
|
+
parts.push(`license: ${cached.license}`);
|
|
476
|
+
if (cached.architectures) {
|
|
477
|
+
try {
|
|
478
|
+
const archs = JSON.parse(cached.architectures);
|
|
479
|
+
if (archs.length)
|
|
480
|
+
parts.push(`HF arch: ${archs.join(', ')}`);
|
|
481
|
+
}
|
|
482
|
+
catch { /* skip */ }
|
|
483
|
+
}
|
|
484
|
+
return parts.length > 0 ? ` HuggingFace: ${parts.join(' · ')}` : '';
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Get all cached profiles (for diagnostics or export).
|
|
488
|
+
*/
|
|
489
|
+
export async function getAllCachedProfiles() {
|
|
490
|
+
const database = await initDb();
|
|
491
|
+
const results = [];
|
|
492
|
+
const stmt = database.prepare('SELECT * FROM model_profiles ORDER BY model_id');
|
|
493
|
+
while (stmt.step()) {
|
|
494
|
+
const row = stmt.getAsObject();
|
|
495
|
+
results.push({
|
|
496
|
+
modelId: row.model_id,
|
|
497
|
+
hfId: row.hf_id,
|
|
498
|
+
pipelineTag: row.pipeline_tag,
|
|
499
|
+
architectures: row.architectures,
|
|
500
|
+
license: row.license,
|
|
501
|
+
downloads: row.downloads,
|
|
502
|
+
likes: row.likes,
|
|
503
|
+
libraryName: row.library_name,
|
|
504
|
+
family: row.family,
|
|
505
|
+
description: row.description,
|
|
506
|
+
strengths: row.strengths,
|
|
507
|
+
weaknesses: row.weaknesses,
|
|
508
|
+
bestFor: row.best_for,
|
|
509
|
+
fetchedAt: row.fetched_at,
|
|
510
|
+
source: row.source,
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
stmt.free();
|
|
514
|
+
return results;
|
|
515
|
+
}
|
|
516
|
+
//# sourceMappingURL=model-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-cache.js","sourceRoot":"","sources":["../src/model-cache.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@houtini/lm",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MCP server for local LLMs — connects to LM Studio or any OpenAI-compatible endpoint",
|
|
6
6
|
"mcpName": "io.github.houtini-ai/lm",
|
|
@@ -44,10 +44,12 @@
|
|
|
44
44
|
"url": "https://github.com/sponsors/houtini-ai"
|
|
45
45
|
},
|
|
46
46
|
"dependencies": {
|
|
47
|
-
"@modelcontextprotocol/sdk": "^1.26.0"
|
|
47
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
48
|
+
"sql.js": "^1.14.1"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
51
|
"@types/node": "^22.0.0",
|
|
52
|
+
"@types/sql.js": "^1.4.9",
|
|
51
53
|
"typescript": "^5.7.0"
|
|
52
54
|
},
|
|
53
55
|
"engines": {
|
package/server.json
CHANGED
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
-
"name": "Houtini LM",
|
|
4
|
-
"description": "MCP server that connects Claude to any OpenAI-compatible LLM endpoint. Offload routine analysis to a local model and preserve your Claude context window.",
|
|
5
|
-
"icon": "https://houtini.ai/favicon.ico",
|
|
6
|
-
"repository": {
|
|
7
|
-
"url": "https://github.com/houtini-ai/lm",
|
|
8
|
-
"source": "github"
|
|
9
|
-
},
|
|
10
|
-
"version": "2.0
|
|
11
|
-
"packages": [
|
|
12
|
-
{
|
|
13
|
-
"registryType": "npm",
|
|
14
|
-
"identifier": "@houtini/lm",
|
|
15
|
-
"version": "2.0
|
|
16
|
-
"transport": [
|
|
17
|
-
{
|
|
18
|
-
"type": "stdio"
|
|
19
|
-
}
|
|
20
|
-
],
|
|
21
|
-
"environmentVariables": [
|
|
22
|
-
{
|
|
23
|
-
"name": "LM_STUDIO_URL",
|
|
24
|
-
"description": "Base URL of the OpenAI-compatible API endpoint",
|
|
25
|
-
"isRequired": false,
|
|
26
|
-
"format": "url"
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
"name": "LM_STUDIO_MODEL",
|
|
30
|
-
"description": "Model identifier to use for requests (auto-detected if not set)",
|
|
31
|
-
"isRequired": false,
|
|
32
|
-
"format": "string"
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
"name": "LM_STUDIO_PASSWORD",
|
|
36
|
-
"description": "Bearer token for API authentication (no auth if blank)",
|
|
37
|
-
"isRequired": false,
|
|
38
|
-
"isSecret": true,
|
|
39
|
-
"format": "string"
|
|
40
|
-
}
|
|
41
|
-
]
|
|
42
|
-
}
|
|
43
|
-
]
|
|
44
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
|
+
"name": "Houtini LM",
|
|
4
|
+
"description": "MCP server that connects Claude to any OpenAI-compatible LLM endpoint. Offload routine analysis to a local model and preserve your Claude context window.",
|
|
5
|
+
"icon": "https://houtini.ai/favicon.ico",
|
|
6
|
+
"repository": {
|
|
7
|
+
"url": "https://github.com/houtini-ai/lm",
|
|
8
|
+
"source": "github"
|
|
9
|
+
},
|
|
10
|
+
"version": "2.7.0",
|
|
11
|
+
"packages": [
|
|
12
|
+
{
|
|
13
|
+
"registryType": "npm",
|
|
14
|
+
"identifier": "@houtini/lm",
|
|
15
|
+
"version": "2.7.0",
|
|
16
|
+
"transport": [
|
|
17
|
+
{
|
|
18
|
+
"type": "stdio"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
"environmentVariables": [
|
|
22
|
+
{
|
|
23
|
+
"name": "LM_STUDIO_URL",
|
|
24
|
+
"description": "Base URL of the OpenAI-compatible API endpoint",
|
|
25
|
+
"isRequired": false,
|
|
26
|
+
"format": "url"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"name": "LM_STUDIO_MODEL",
|
|
30
|
+
"description": "Model identifier to use for requests (auto-detected if not set)",
|
|
31
|
+
"isRequired": false,
|
|
32
|
+
"format": "string"
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "LM_STUDIO_PASSWORD",
|
|
36
|
+
"description": "Bearer token for API authentication (no auth if blank)",
|
|
37
|
+
"isRequired": false,
|
|
38
|
+
"isSecret": true,
|
|
39
|
+
"format": "string"
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
]
|
|
44
|
+
}
|