@loreai/core 0.16.0 → 0.17.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.
Files changed (155) hide show
  1. package/README.md +11 -0
  2. package/dist/bun/agents-file.d.ts +13 -1
  3. package/dist/bun/agents-file.d.ts.map +1 -1
  4. package/dist/bun/config.d.ts +20 -1
  5. package/dist/bun/config.d.ts.map +1 -1
  6. package/dist/bun/data.d.ts +174 -0
  7. package/dist/bun/data.d.ts.map +1 -0
  8. package/dist/bun/db.d.ts +65 -0
  9. package/dist/bun/db.d.ts.map +1 -1
  10. package/dist/bun/distillation.d.ts +49 -6
  11. package/dist/bun/distillation.d.ts.map +1 -1
  12. package/dist/bun/embedding-vendor.d.ts +66 -0
  13. package/dist/bun/embedding-vendor.d.ts.map +1 -0
  14. package/dist/bun/embedding-worker-types.d.ts +66 -0
  15. package/dist/bun/embedding-worker-types.d.ts.map +1 -0
  16. package/dist/bun/embedding-worker.d.ts +16 -0
  17. package/dist/bun/embedding-worker.d.ts.map +1 -0
  18. package/dist/bun/embedding-worker.js +100 -0
  19. package/dist/bun/embedding-worker.js.map +7 -0
  20. package/dist/bun/embedding.d.ts +91 -8
  21. package/dist/bun/embedding.d.ts.map +1 -1
  22. package/dist/bun/git.d.ts +47 -0
  23. package/dist/bun/git.d.ts.map +1 -0
  24. package/dist/bun/gradient.d.ts +19 -1
  25. package/dist/bun/gradient.d.ts.map +1 -1
  26. package/dist/bun/index.d.ts +9 -6
  27. package/dist/bun/index.d.ts.map +1 -1
  28. package/dist/bun/index.js +13029 -10885
  29. package/dist/bun/index.js.map +4 -4
  30. package/dist/bun/lat-reader.d.ts +1 -1
  31. package/dist/bun/lat-reader.d.ts.map +1 -1
  32. package/dist/bun/ltm.d.ts.map +1 -1
  33. package/dist/bun/markdown.d.ts +11 -0
  34. package/dist/bun/markdown.d.ts.map +1 -1
  35. package/dist/bun/prompt.d.ts +1 -1
  36. package/dist/bun/prompt.d.ts.map +1 -1
  37. package/dist/bun/recall.d.ts +53 -0
  38. package/dist/bun/recall.d.ts.map +1 -1
  39. package/dist/bun/search.d.ts +29 -0
  40. package/dist/bun/search.d.ts.map +1 -1
  41. package/dist/bun/temporal.d.ts +2 -0
  42. package/dist/bun/temporal.d.ts.map +1 -1
  43. package/dist/bun/types.d.ts +15 -0
  44. package/dist/bun/types.d.ts.map +1 -1
  45. package/dist/bun/worker-model.d.ts +12 -9
  46. package/dist/bun/worker-model.d.ts.map +1 -1
  47. package/dist/node/agents-file.d.ts +13 -1
  48. package/dist/node/agents-file.d.ts.map +1 -1
  49. package/dist/node/config.d.ts +20 -1
  50. package/dist/node/config.d.ts.map +1 -1
  51. package/dist/node/data.d.ts +174 -0
  52. package/dist/node/data.d.ts.map +1 -0
  53. package/dist/node/db.d.ts +65 -0
  54. package/dist/node/db.d.ts.map +1 -1
  55. package/dist/node/distillation.d.ts +49 -6
  56. package/dist/node/distillation.d.ts.map +1 -1
  57. package/dist/node/embedding-vendor.d.ts +66 -0
  58. package/dist/node/embedding-vendor.d.ts.map +1 -0
  59. package/dist/node/embedding-worker-types.d.ts +66 -0
  60. package/dist/node/embedding-worker-types.d.ts.map +1 -0
  61. package/dist/node/embedding-worker.d.ts +16 -0
  62. package/dist/node/embedding-worker.d.ts.map +1 -0
  63. package/dist/node/embedding-worker.js +100 -0
  64. package/dist/node/embedding-worker.js.map +7 -0
  65. package/dist/node/embedding.d.ts +91 -8
  66. package/dist/node/embedding.d.ts.map +1 -1
  67. package/dist/node/git.d.ts +47 -0
  68. package/dist/node/git.d.ts.map +1 -0
  69. package/dist/node/gradient.d.ts +19 -1
  70. package/dist/node/gradient.d.ts.map +1 -1
  71. package/dist/node/index.d.ts +9 -6
  72. package/dist/node/index.d.ts.map +1 -1
  73. package/dist/node/index.js +13029 -10885
  74. package/dist/node/index.js.map +4 -4
  75. package/dist/node/lat-reader.d.ts +1 -1
  76. package/dist/node/lat-reader.d.ts.map +1 -1
  77. package/dist/node/ltm.d.ts.map +1 -1
  78. package/dist/node/markdown.d.ts +11 -0
  79. package/dist/node/markdown.d.ts.map +1 -1
  80. package/dist/node/prompt.d.ts +1 -1
  81. package/dist/node/prompt.d.ts.map +1 -1
  82. package/dist/node/recall.d.ts +53 -0
  83. package/dist/node/recall.d.ts.map +1 -1
  84. package/dist/node/search.d.ts +29 -0
  85. package/dist/node/search.d.ts.map +1 -1
  86. package/dist/node/temporal.d.ts +2 -0
  87. package/dist/node/temporal.d.ts.map +1 -1
  88. package/dist/node/types.d.ts +15 -0
  89. package/dist/node/types.d.ts.map +1 -1
  90. package/dist/node/worker-model.d.ts +12 -9
  91. package/dist/node/worker-model.d.ts.map +1 -1
  92. package/dist/types/agents-file.d.ts +13 -1
  93. package/dist/types/agents-file.d.ts.map +1 -1
  94. package/dist/types/config.d.ts +20 -1
  95. package/dist/types/config.d.ts.map +1 -1
  96. package/dist/types/data.d.ts +174 -0
  97. package/dist/types/data.d.ts.map +1 -0
  98. package/dist/types/db.d.ts +65 -0
  99. package/dist/types/db.d.ts.map +1 -1
  100. package/dist/types/distillation.d.ts +49 -6
  101. package/dist/types/distillation.d.ts.map +1 -1
  102. package/dist/types/embedding-vendor.d.ts +66 -0
  103. package/dist/types/embedding-vendor.d.ts.map +1 -0
  104. package/dist/types/embedding-worker-types.d.ts +66 -0
  105. package/dist/types/embedding-worker-types.d.ts.map +1 -0
  106. package/dist/types/embedding-worker.d.ts +16 -0
  107. package/dist/types/embedding-worker.d.ts.map +1 -0
  108. package/dist/types/embedding.d.ts +91 -8
  109. package/dist/types/embedding.d.ts.map +1 -1
  110. package/dist/types/git.d.ts +47 -0
  111. package/dist/types/git.d.ts.map +1 -0
  112. package/dist/types/gradient.d.ts +19 -1
  113. package/dist/types/gradient.d.ts.map +1 -1
  114. package/dist/types/index.d.ts +9 -6
  115. package/dist/types/index.d.ts.map +1 -1
  116. package/dist/types/lat-reader.d.ts +1 -1
  117. package/dist/types/lat-reader.d.ts.map +1 -1
  118. package/dist/types/ltm.d.ts.map +1 -1
  119. package/dist/types/markdown.d.ts +11 -0
  120. package/dist/types/markdown.d.ts.map +1 -1
  121. package/dist/types/prompt.d.ts +1 -1
  122. package/dist/types/prompt.d.ts.map +1 -1
  123. package/dist/types/recall.d.ts +53 -0
  124. package/dist/types/recall.d.ts.map +1 -1
  125. package/dist/types/search.d.ts +29 -0
  126. package/dist/types/search.d.ts.map +1 -1
  127. package/dist/types/temporal.d.ts +2 -0
  128. package/dist/types/temporal.d.ts.map +1 -1
  129. package/dist/types/types.d.ts +15 -0
  130. package/dist/types/types.d.ts.map +1 -1
  131. package/dist/types/worker-model.d.ts +12 -9
  132. package/dist/types/worker-model.d.ts.map +1 -1
  133. package/package.json +5 -2
  134. package/src/agents-file.ts +87 -4
  135. package/src/config.ts +68 -5
  136. package/src/curator.ts +2 -2
  137. package/src/data.ts +768 -0
  138. package/src/db.ts +386 -7
  139. package/src/distillation.ts +178 -35
  140. package/src/embedding-vendor.ts +102 -0
  141. package/src/embedding-worker-types.ts +82 -0
  142. package/src/embedding-worker.ts +185 -0
  143. package/src/embedding.ts +607 -61
  144. package/src/git.ts +144 -0
  145. package/src/gradient.ts +174 -17
  146. package/src/index.ts +20 -0
  147. package/src/lat-reader.ts +5 -11
  148. package/src/ltm.ts +17 -44
  149. package/src/markdown.ts +15 -0
  150. package/src/prompt.ts +1 -2
  151. package/src/recall.ts +401 -70
  152. package/src/search.ts +71 -1
  153. package/src/temporal.ts +42 -35
  154. package/src/types.ts +15 -0
  155. package/src/worker-model.ts +14 -9
package/src/temporal.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { db, ensureProject } from "./db";
2
- import { ftsQuery, ftsQueryOr, EMPTY_QUERY } from "./search";
2
+ import { ftsQuery, EMPTY_QUERY, runRelaxedSearch } from "./search";
3
3
  import { sanitizeSurrogates } from "./markdown";
4
+ import * as embedding from "./embedding";
4
5
  import type { LoreMessage, LorePart } from "./types";
5
6
  import { isTextPart, isReasoningPart, isToolPart } from "./types";
6
7
 
@@ -93,6 +94,10 @@ export function store(input: {
93
94
  messageMetadata(input.info, input.parts),
94
95
  input.info.id,
95
96
  );
97
+ // Re-embed on content update (fire-and-forget)
98
+ if (embedding.isAvailable()) {
99
+ embedding.embedTemporalMessage(input.info.id, content);
100
+ }
96
101
  return;
97
102
  }
98
103
 
@@ -111,6 +116,11 @@ export function store(input: {
111
116
  input.info.time.created,
112
117
  messageMetadata(input.info, input.parts),
113
118
  );
119
+
120
+ // Embed new message for vector search (fire-and-forget)
121
+ if (embedding.isAvailable()) {
122
+ embedding.embedTemporalMessage(input.info.id, content);
123
+ }
114
124
  }
115
125
 
116
126
  export type TemporalMessage = {
@@ -156,7 +166,7 @@ export function markDistilled(ids: string[]) {
156
166
  const placeholders = ids.map(() => "?").join(",");
157
167
  db()
158
168
  .query(
159
- `UPDATE temporal_messages SET distilled = 1 WHERE id IN (${placeholders})`,
169
+ `UPDATE temporal_messages SET distilled = 1, embedding = NULL WHERE id IN (${placeholders})`,
160
170
  )
161
171
  .run(...ids);
162
172
  }
@@ -194,8 +204,6 @@ export function search(input: {
194
204
  }): TemporalMessage[] {
195
205
  const pid = ensureProject(input.projectPath);
196
206
  const limit = input.limit ?? 20;
197
- const q = ftsQuery(input.query);
198
- if (q === EMPTY_QUERY) return [];
199
207
 
200
208
  const ftsSQL = input.sessionID
201
209
  ? `SELECT m.* FROM temporal_fts f
@@ -206,24 +214,14 @@ export function search(input: {
206
214
  CROSS JOIN temporal_messages m ON m.rowid = f.rowid
207
215
  WHERE f.content MATCH ? AND m.project_id = ?
208
216
  ORDER BY rank LIMIT ?`;
209
- const params = input.sessionID
210
- ? [q, pid, input.sessionID, limit]
211
- : [q, pid, limit];
217
+
212
218
  try {
213
- const results = db()
214
- .query(ftsSQL)
215
- .all(...params) as TemporalMessage[];
216
- if (results.length) return results;
217
-
218
- // AND returned nothing — try OR fallback for broader recall
219
- const qOr = ftsQueryOr(input.query);
220
- if (qOr === EMPTY_QUERY) return [];
221
- const paramsOr = input.sessionID
222
- ? [qOr, pid, input.sessionID, limit]
223
- : [qOr, pid, limit];
224
- return db()
225
- .query(ftsSQL)
226
- .all(...paramsOr) as TemporalMessage[];
219
+ return runRelaxedSearch(input.query, (matchExpr) => {
220
+ const params = input.sessionID
221
+ ? [matchExpr, pid, input.sessionID, limit]
222
+ : [matchExpr, pid, limit];
223
+ return db().query(ftsSQL).all(...params) as TemporalMessage[];
224
+ });
227
225
  } catch {
228
226
  // FTS5 still choked (edge case) — fall back to LIKE search
229
227
  return searchLike({
@@ -249,8 +247,6 @@ export function searchScored(input: {
249
247
  }): ScoredTemporalMessage[] {
250
248
  const pid = ensureProject(input.projectPath);
251
249
  const limit = input.limit ?? 20;
252
- const q = ftsQuery(input.query);
253
- if (q === EMPTY_QUERY) return [];
254
250
 
255
251
  const ftsSQL = input.sessionID
256
252
  ? `SELECT m.*, rank FROM temporal_fts f
@@ -261,20 +257,14 @@ export function searchScored(input: {
261
257
  CROSS JOIN temporal_messages m ON m.rowid = f.rowid
262
258
  WHERE f.content MATCH ? AND m.project_id = ?
263
259
  ORDER BY rank LIMIT ?`;
264
- const params = input.sessionID
265
- ? [q, pid, input.sessionID, limit]
266
- : [q, pid, limit];
267
260
 
268
261
  try {
269
- const results = db().query(ftsSQL).all(...params) as ScoredTemporalMessage[];
270
- if (results.length) return results;
271
-
272
- const qOr = ftsQueryOr(input.query);
273
- if (qOr === EMPTY_QUERY) return [];
274
- const paramsOr = input.sessionID
275
- ? [qOr, pid, input.sessionID, limit]
276
- : [qOr, pid, limit];
277
- return db().query(ftsSQL).all(...paramsOr) as ScoredTemporalMessage[];
262
+ return runRelaxedSearch(input.query, (matchExpr) => {
263
+ const params = input.sessionID
264
+ ? [matchExpr, pid, input.sessionID, limit]
265
+ : [matchExpr, pid, limit];
266
+ return db().query(ftsSQL).all(...params) as ScoredTemporalMessage[];
267
+ });
278
268
  } catch {
279
269
  return [];
280
270
  }
@@ -348,6 +338,23 @@ export function undistilledCount(
348
338
  ).count;
349
339
  }
350
340
 
341
+ /** Sum of estimated tokens across undistilled messages for a project/session. */
342
+ export function undistilledTokens(
343
+ projectPath: string,
344
+ sessionID?: string,
345
+ ): number {
346
+ const pid = ensureProject(projectPath);
347
+ const query = sessionID
348
+ ? "SELECT COALESCE(SUM(tokens), 0) as total FROM temporal_messages WHERE project_id = ? AND session_id = ? AND distilled = 0"
349
+ : "SELECT COALESCE(SUM(tokens), 0) as total FROM temporal_messages WHERE project_id = ? AND distilled = 0";
350
+ const params = sessionID ? [pid, sessionID] : [pid];
351
+ return (
352
+ db()
353
+ .query(query)
354
+ .get(...params) as { total: number }
355
+ ).total;
356
+ }
357
+
351
358
  export type PruneResult = {
352
359
  /** Rows deleted by the TTL pass (distilled=1 AND older than retention period). */
353
360
  ttlDeleted: number;
package/src/types.ts CHANGED
@@ -245,6 +245,21 @@ export interface LLMClient {
245
245
  * auth through their own mechanisms.
246
246
  */
247
247
  sessionID?: string;
248
+ /**
249
+ * Maximum output tokens for this call. When absent, the adapter
250
+ * uses its built-in default (typically 8192).
251
+ *
252
+ * Worker call sites should set this explicitly based on expected
253
+ * output size to avoid wasting tokens on unnecessarily large
254
+ * output budgets.
255
+ *
256
+ * Adapter behavior:
257
+ * - Gateway: uses as `max_tokens` in the API request body
258
+ * - Pi: passes as `maxTokens` to `complete()`
259
+ * - OpenCode: cannot honor — SDK has no maxTokens on session.prompt();
260
+ * the field is silently ignored
261
+ */
262
+ maxTokens?: number;
248
263
  },
249
264
  ): Promise<string | null>;
250
265
  }
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * Worker model resolution.
3
3
  *
4
- * Background workers (distillation, curation, query expansion) use the session
5
- * model by default. An explicit `workerModel` config override is supported for
6
- * cases where the user wants to pin background work to a specific model.
4
+ * Background workers (distillation, curation, query expansion) default to
5
+ * sonnet-4-6 when the session model is more expensive ($1.50+/M input).
6
+ * Sonnet-4-6 produces equivalent-quality distillations at lower cost.
7
+ * An explicit `workerModel` config override takes priority over this default.
7
8
  *
8
- * Previously this module contained dynamic worker model selection with
9
- * candidate discovery, two-phase validation (structural check + LLM judge),
10
- * and fingerprint-based staleness detection. That complexity was removed in
11
- * favor of always using the session model A/B testing showed the quality
12
- * gap on complex conversations wasn't worth the infrastructure cost.
9
+ * Resolution order:
10
+ * 1. Explicit config override (`workerModel`)
11
+ * 2. Cost-aware default (sonnet-4 for expensive session models)
12
+ * 3. Session model fallback (same model as the conversation)
13
13
  */
14
14
 
15
15
  // ---------------------------------------------------------------------------
@@ -35,16 +35,21 @@ export type ModelInfo = {
35
35
 
36
36
  /**
37
37
  * Resolve the effective worker model for a given provider.
38
- * Priority: explicit config override > session model (fallback).
38
+ * Priority: explicit config override > cost-aware default > session model.
39
39
  */
40
40
  export function resolveWorkerModel(
41
41
  _providerID: string,
42
42
  configWorkerModel?: { providerID: string; modelID: string },
43
43
  configModel?: { providerID: string; modelID: string },
44
+ costAwareDefault?: { providerID: string; modelID: string },
44
45
  ): { providerID: string; modelID: string } | undefined {
45
46
  // Explicit override wins
46
47
  if (configWorkerModel) return configWorkerModel;
47
48
 
49
+ // Cost-aware default: cheaper model for background work when the session
50
+ // model is expensive. Caller determines when this applies based on pricing.
51
+ if (costAwareDefault) return costAwareDefault;
52
+
48
53
  // Fall back to the session model config (or undefined = host default)
49
54
  return configModel;
50
55
  }