@loreai/core 0.11.1 → 0.13.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/dist/bun/agents-file.d.ts +29 -8
- package/dist/bun/agents-file.d.ts.map +1 -1
- package/dist/bun/config.d.ts +1 -0
- package/dist/bun/config.d.ts.map +1 -1
- package/dist/bun/db.d.ts.map +1 -1
- package/dist/bun/distillation.d.ts +55 -0
- package/dist/bun/distillation.d.ts.map +1 -1
- package/dist/bun/embedding.d.ts +15 -1
- package/dist/bun/embedding.d.ts.map +1 -1
- package/dist/bun/gradient.d.ts +53 -5
- package/dist/bun/gradient.d.ts.map +1 -1
- package/dist/bun/index.d.ts +4 -4
- package/dist/bun/index.d.ts.map +1 -1
- package/dist/bun/index.js +799 -256
- package/dist/bun/index.js.map +4 -4
- package/dist/bun/pattern-extract.d.ts +36 -0
- package/dist/bun/pattern-extract.d.ts.map +1 -0
- package/dist/bun/recall.d.ts +1 -0
- package/dist/bun/recall.d.ts.map +1 -1
- package/dist/bun/search.d.ts +13 -1
- package/dist/bun/search.d.ts.map +1 -1
- package/dist/bun/temporal.d.ts +15 -0
- package/dist/bun/temporal.d.ts.map +1 -1
- package/dist/bun/types.d.ts +41 -1
- package/dist/bun/types.d.ts.map +1 -1
- package/dist/bun/worker-model.d.ts +22 -0
- package/dist/bun/worker-model.d.ts.map +1 -1
- package/dist/node/agents-file.d.ts +29 -8
- package/dist/node/agents-file.d.ts.map +1 -1
- package/dist/node/config.d.ts +1 -0
- package/dist/node/config.d.ts.map +1 -1
- package/dist/node/db.d.ts.map +1 -1
- package/dist/node/distillation.d.ts +55 -0
- package/dist/node/distillation.d.ts.map +1 -1
- package/dist/node/embedding.d.ts +15 -1
- package/dist/node/embedding.d.ts.map +1 -1
- package/dist/node/gradient.d.ts +53 -5
- package/dist/node/gradient.d.ts.map +1 -1
- package/dist/node/index.d.ts +4 -4
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +799 -256
- package/dist/node/index.js.map +4 -4
- package/dist/node/pattern-extract.d.ts +36 -0
- package/dist/node/pattern-extract.d.ts.map +1 -0
- package/dist/node/recall.d.ts +1 -0
- package/dist/node/recall.d.ts.map +1 -1
- package/dist/node/search.d.ts +13 -1
- package/dist/node/search.d.ts.map +1 -1
- package/dist/node/temporal.d.ts +15 -0
- package/dist/node/temporal.d.ts.map +1 -1
- package/dist/node/types.d.ts +41 -1
- package/dist/node/types.d.ts.map +1 -1
- package/dist/node/worker-model.d.ts +22 -0
- package/dist/node/worker-model.d.ts.map +1 -1
- package/dist/types/agents-file.d.ts +29 -8
- package/dist/types/agents-file.d.ts.map +1 -1
- package/dist/types/config.d.ts +1 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/db.d.ts.map +1 -1
- package/dist/types/distillation.d.ts +55 -0
- package/dist/types/distillation.d.ts.map +1 -1
- package/dist/types/embedding.d.ts +15 -1
- package/dist/types/embedding.d.ts.map +1 -1
- package/dist/types/gradient.d.ts +53 -5
- package/dist/types/gradient.d.ts.map +1 -1
- package/dist/types/index.d.ts +4 -4
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/pattern-extract.d.ts +36 -0
- package/dist/types/pattern-extract.d.ts.map +1 -0
- package/dist/types/recall.d.ts +1 -0
- package/dist/types/recall.d.ts.map +1 -1
- package/dist/types/search.d.ts +13 -1
- package/dist/types/search.d.ts.map +1 -1
- package/dist/types/temporal.d.ts +15 -0
- package/dist/types/temporal.d.ts.map +1 -1
- package/dist/types/types.d.ts +41 -1
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/worker-model.d.ts +22 -0
- package/dist/types/worker-model.d.ts.map +1 -1
- package/package.json +3 -2
- package/src/agents-file.ts +111 -28
- package/src/config.ts +25 -18
- package/src/curator.ts +2 -2
- package/src/db.ts +83 -4
- package/src/distillation.ts +270 -27
- package/src/embedding.ts +158 -14
- package/src/gradient.ts +398 -227
- package/src/index.ts +13 -5
- package/src/pattern-extract.ts +108 -0
- package/src/recall.ts +142 -6
- package/src/search.ts +37 -1
- package/src/temporal.ts +39 -0
- package/src/types.ts +41 -1
- package/src/worker-model.ts +142 -5
package/src/worker-model.ts
CHANGED
|
@@ -25,7 +25,11 @@ export type ModelInfo = {
|
|
|
25
25
|
providerID: string;
|
|
26
26
|
cost: { input: number }; // per-token cost
|
|
27
27
|
status: string;
|
|
28
|
-
capabilities: {
|
|
28
|
+
capabilities: {
|
|
29
|
+
input: { text: boolean };
|
|
30
|
+
/** Whether this model supports extended thinking/reasoning. */
|
|
31
|
+
reasoning?: boolean;
|
|
32
|
+
};
|
|
29
33
|
};
|
|
30
34
|
|
|
31
35
|
/** Result of a worker model validation stored in kv_meta. */
|
|
@@ -64,8 +68,17 @@ export function selectWorkerCandidates(
|
|
|
64
68
|
|
|
65
69
|
if (eligible.length === 0) return [];
|
|
66
70
|
|
|
67
|
-
// Sort by cost ascending
|
|
68
|
-
|
|
71
|
+
// Sort by cost ascending, then prefer non-reasoning models at equal cost.
|
|
72
|
+
// Non-reasoning models don't produce thinking tokens, avoiding wasted spend
|
|
73
|
+
// on tokens that background workers discard.
|
|
74
|
+
const sorted = [...eligible].sort((a, b) => {
|
|
75
|
+
const costDiff = a.cost.input - b.cost.input;
|
|
76
|
+
if (costDiff !== 0) return costDiff;
|
|
77
|
+
// At equal cost, non-reasoning (0) sorts before reasoning (1)
|
|
78
|
+
const aReasoning = a.capabilities.reasoning ? 1 : 0;
|
|
79
|
+
const bReasoning = b.capabilities.reasoning ? 1 : 0;
|
|
80
|
+
return aReasoning - bReasoning;
|
|
81
|
+
});
|
|
69
82
|
|
|
70
83
|
// Cheapest overall
|
|
71
84
|
const cheapest = sorted[0];
|
|
@@ -139,6 +152,11 @@ export function storeValidatedWorkerModel(result: WorkerModelResult): void {
|
|
|
139
152
|
.run(key, value, value);
|
|
140
153
|
}
|
|
141
154
|
|
|
155
|
+
/** Clear a stored worker model validation (e.g. when the model is deprecated). */
|
|
156
|
+
export function clearValidatedWorkerModel(providerID: string): void {
|
|
157
|
+
db().query("DELETE FROM kv_meta WHERE key = ?").run(`${KV_PREFIX}${providerID}`);
|
|
158
|
+
}
|
|
159
|
+
|
|
142
160
|
/**
|
|
143
161
|
* Check whether the stored validation is stale (fingerprint mismatch).
|
|
144
162
|
*/
|
|
@@ -237,6 +255,122 @@ export function parseJudgeScore(response: string): number | null {
|
|
|
237
255
|
return parseInt(match[1], 10);
|
|
238
256
|
}
|
|
239
257
|
|
|
258
|
+
// ---------------------------------------------------------------------------
|
|
259
|
+
// Validation orchestration
|
|
260
|
+
// ---------------------------------------------------------------------------
|
|
261
|
+
|
|
262
|
+
import { DISTILLATION_SYSTEM, distillationUser } from "./prompt";
|
|
263
|
+
import type { LLMClient } from "./types";
|
|
264
|
+
|
|
265
|
+
export type ValidationInput = {
|
|
266
|
+
llm: LLMClient;
|
|
267
|
+
providerID: string;
|
|
268
|
+
sessionModelID: string;
|
|
269
|
+
candidates: ModelInfo[];
|
|
270
|
+
/** Recent gen-0 distillation to use as reference (observations text). */
|
|
271
|
+
referenceObservations: string;
|
|
272
|
+
/** Source messages text for re-running distillation with candidates. */
|
|
273
|
+
sourceMessagesText: string;
|
|
274
|
+
/** Date string for the distillation prompt. */
|
|
275
|
+
date: string;
|
|
276
|
+
};
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Run the two-phase quality validation for worker model candidates.
|
|
280
|
+
* Returns the cheapest passing candidate, or null if none pass.
|
|
281
|
+
*/
|
|
282
|
+
export async function runValidation(
|
|
283
|
+
input: ValidationInput,
|
|
284
|
+
): Promise<WorkerModelResult | null> {
|
|
285
|
+
const { llm, candidates, referenceObservations, sourceMessagesText, date } = input;
|
|
286
|
+
|
|
287
|
+
const userPrompt = distillationUser({
|
|
288
|
+
messages: sourceMessagesText,
|
|
289
|
+
date,
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
for (const candidate of candidates) {
|
|
293
|
+
// Skip the session model — it produced the reference, no need to test
|
|
294
|
+
if (candidate.id === input.sessionModelID) continue;
|
|
295
|
+
|
|
296
|
+
// Phase 1: run distillation with candidate model
|
|
297
|
+
let candidateObservations: string | null = null;
|
|
298
|
+
try {
|
|
299
|
+
const raw = await llm.prompt(DISTILLATION_SYSTEM, userPrompt, {
|
|
300
|
+
model: { providerID: candidate.providerID, modelID: candidate.id },
|
|
301
|
+
workerID: "lore-distill",
|
|
302
|
+
thinking: false,
|
|
303
|
+
});
|
|
304
|
+
if (raw) {
|
|
305
|
+
// Parse <observations>...</observations> block
|
|
306
|
+
const match = raw.match(/<observations>([\s\S]*?)<\/observations>/);
|
|
307
|
+
candidateObservations = match ? match[1].trim() : raw.trim();
|
|
308
|
+
}
|
|
309
|
+
} catch (e) {
|
|
310
|
+
log.warn(`worker model validation: candidate ${candidate.id} failed:`, e);
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
const structural = structuralCheck(candidateObservations, referenceObservations);
|
|
315
|
+
if (!structural.passed) {
|
|
316
|
+
log.info(
|
|
317
|
+
`worker model validation: ${candidate.id} failed structural check: ${structural.reason}`,
|
|
318
|
+
);
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Phase 2: LLM judge (using session model)
|
|
323
|
+
let judgeScore: number | null = null;
|
|
324
|
+
try {
|
|
325
|
+
const judgeResponse = await llm.prompt(
|
|
326
|
+
WORKER_JUDGE_SYSTEM,
|
|
327
|
+
workerJudgeUser(referenceObservations, candidateObservations!),
|
|
328
|
+
{ workerID: "lore-distill", thinking: false }, // use session model (no model override)
|
|
329
|
+
);
|
|
330
|
+
if (judgeResponse) {
|
|
331
|
+
judgeScore = parseJudgeScore(judgeResponse);
|
|
332
|
+
}
|
|
333
|
+
} catch (e) {
|
|
334
|
+
log.warn(`worker model validation: judge call failed for ${candidate.id}:`, e);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
if (judgeScore !== null && judgeScore < 3) {
|
|
338
|
+
log.info(
|
|
339
|
+
`worker model validation: ${candidate.id} failed judge (score=${judgeScore})`,
|
|
340
|
+
);
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// Candidate passed both phases
|
|
345
|
+
const fingerprint = computeModelFingerprint(
|
|
346
|
+
input.providerID,
|
|
347
|
+
input.sessionModelID,
|
|
348
|
+
candidates.map((c) => c.id),
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
const result: WorkerModelResult = {
|
|
352
|
+
modelID: candidate.id,
|
|
353
|
+
providerID: candidate.providerID,
|
|
354
|
+
fingerprint,
|
|
355
|
+
validatedAt: Date.now(),
|
|
356
|
+
judgeScore,
|
|
357
|
+
};
|
|
358
|
+
storeValidatedWorkerModel(result);
|
|
359
|
+
log.info(
|
|
360
|
+
`worker model validated: ${candidate.id} (judge=${judgeScore}) for provider ${input.providerID}`,
|
|
361
|
+
);
|
|
362
|
+
return result;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// No candidate passed — clear any stale stored result so we don't keep
|
|
366
|
+
// routing worker calls to a potentially-deprecated model.
|
|
367
|
+
clearValidatedWorkerModel(input.providerID);
|
|
368
|
+
log.info(
|
|
369
|
+
`worker model validation: no candidate passed for ${input.providerID} — cleared stale entry`,
|
|
370
|
+
);
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
|
|
240
374
|
// ---------------------------------------------------------------------------
|
|
241
375
|
// Effective worker model resolution
|
|
242
376
|
// ---------------------------------------------------------------------------
|
|
@@ -253,9 +387,12 @@ export function resolveWorkerModel(
|
|
|
253
387
|
// Explicit override wins
|
|
254
388
|
if (configWorkerModel) return configWorkerModel;
|
|
255
389
|
|
|
256
|
-
// Check for validated auto-selection
|
|
390
|
+
// Check for validated auto-selection.
|
|
391
|
+
// Don't trust entries older than 24h — model may have been deprecated.
|
|
392
|
+
// Validation will re-run on next idle cycle and either re-confirm or clear.
|
|
257
393
|
const validated = getValidatedWorkerModel(providerID);
|
|
258
|
-
|
|
394
|
+
const MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
395
|
+
if (validated && Date.now() - validated.validatedAt <= MAX_AGE_MS) {
|
|
259
396
|
return { providerID: validated.providerID, modelID: validated.modelID };
|
|
260
397
|
}
|
|
261
398
|
|