@loreai/core 0.12.0 → 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.
Files changed (87) hide show
  1. package/dist/bun/agents-file.d.ts +29 -8
  2. package/dist/bun/agents-file.d.ts.map +1 -1
  3. package/dist/bun/config.d.ts +1 -0
  4. package/dist/bun/config.d.ts.map +1 -1
  5. package/dist/bun/db.d.ts.map +1 -1
  6. package/dist/bun/distillation.d.ts +29 -0
  7. package/dist/bun/distillation.d.ts.map +1 -1
  8. package/dist/bun/embedding.d.ts +15 -1
  9. package/dist/bun/embedding.d.ts.map +1 -1
  10. package/dist/bun/gradient.d.ts +53 -5
  11. package/dist/bun/gradient.d.ts.map +1 -1
  12. package/dist/bun/index.d.ts +4 -4
  13. package/dist/bun/index.d.ts.map +1 -1
  14. package/dist/bun/index.js +696 -243
  15. package/dist/bun/index.js.map +4 -4
  16. package/dist/bun/pattern-extract.d.ts +36 -0
  17. package/dist/bun/pattern-extract.d.ts.map +1 -0
  18. package/dist/bun/recall.d.ts +1 -0
  19. package/dist/bun/recall.d.ts.map +1 -1
  20. package/dist/bun/search.d.ts +13 -1
  21. package/dist/bun/search.d.ts.map +1 -1
  22. package/dist/bun/types.d.ts +41 -1
  23. package/dist/bun/types.d.ts.map +1 -1
  24. package/dist/bun/worker-model.d.ts +22 -0
  25. package/dist/bun/worker-model.d.ts.map +1 -1
  26. package/dist/node/agents-file.d.ts +29 -8
  27. package/dist/node/agents-file.d.ts.map +1 -1
  28. package/dist/node/config.d.ts +1 -0
  29. package/dist/node/config.d.ts.map +1 -1
  30. package/dist/node/db.d.ts.map +1 -1
  31. package/dist/node/distillation.d.ts +29 -0
  32. package/dist/node/distillation.d.ts.map +1 -1
  33. package/dist/node/embedding.d.ts +15 -1
  34. package/dist/node/embedding.d.ts.map +1 -1
  35. package/dist/node/gradient.d.ts +53 -5
  36. package/dist/node/gradient.d.ts.map +1 -1
  37. package/dist/node/index.d.ts +4 -4
  38. package/dist/node/index.d.ts.map +1 -1
  39. package/dist/node/index.js +696 -243
  40. package/dist/node/index.js.map +4 -4
  41. package/dist/node/pattern-extract.d.ts +36 -0
  42. package/dist/node/pattern-extract.d.ts.map +1 -0
  43. package/dist/node/recall.d.ts +1 -0
  44. package/dist/node/recall.d.ts.map +1 -1
  45. package/dist/node/search.d.ts +13 -1
  46. package/dist/node/search.d.ts.map +1 -1
  47. package/dist/node/types.d.ts +41 -1
  48. package/dist/node/types.d.ts.map +1 -1
  49. package/dist/node/worker-model.d.ts +22 -0
  50. package/dist/node/worker-model.d.ts.map +1 -1
  51. package/dist/types/agents-file.d.ts +29 -8
  52. package/dist/types/agents-file.d.ts.map +1 -1
  53. package/dist/types/config.d.ts +1 -0
  54. package/dist/types/config.d.ts.map +1 -1
  55. package/dist/types/db.d.ts.map +1 -1
  56. package/dist/types/distillation.d.ts +29 -0
  57. package/dist/types/distillation.d.ts.map +1 -1
  58. package/dist/types/embedding.d.ts +15 -1
  59. package/dist/types/embedding.d.ts.map +1 -1
  60. package/dist/types/gradient.d.ts +53 -5
  61. package/dist/types/gradient.d.ts.map +1 -1
  62. package/dist/types/index.d.ts +4 -4
  63. package/dist/types/index.d.ts.map +1 -1
  64. package/dist/types/pattern-extract.d.ts +36 -0
  65. package/dist/types/pattern-extract.d.ts.map +1 -0
  66. package/dist/types/recall.d.ts +1 -0
  67. package/dist/types/recall.d.ts.map +1 -1
  68. package/dist/types/search.d.ts +13 -1
  69. package/dist/types/search.d.ts.map +1 -1
  70. package/dist/types/types.d.ts +41 -1
  71. package/dist/types/types.d.ts.map +1 -1
  72. package/dist/types/worker-model.d.ts +22 -0
  73. package/dist/types/worker-model.d.ts.map +1 -1
  74. package/package.json +3 -2
  75. package/src/agents-file.ts +111 -28
  76. package/src/config.ts +25 -18
  77. package/src/curator.ts +2 -2
  78. package/src/db.ts +19 -2
  79. package/src/distillation.ts +152 -15
  80. package/src/embedding.ts +158 -14
  81. package/src/gradient.ts +398 -227
  82. package/src/index.ts +13 -5
  83. package/src/pattern-extract.ts +108 -0
  84. package/src/recall.ts +124 -6
  85. package/src/search.ts +37 -1
  86. package/src/types.ts +41 -1
  87. package/src/worker-model.ts +142 -5
@@ -1 +1 @@
1
- {"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../../src/recall.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAczC,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;AAEtE,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,mFAAmF;IACnF,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;CACrC,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AA+JlC,wFAAwF;AACxF,wBAAsB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAuOzE;AAED,sEAAsE;AACtE,eAAO,MAAM,uBAAuB,wiBAC8f,CAAC;AAEniB,mEAAmE;AACnE,eAAO,MAAM,yBAAyB;;;CAIrC,CAAC"}
1
+ {"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../../src/recall.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAC3C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAgBzC,KAAK,YAAY,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,YAAY,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjE,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,CAAC;AAEtE,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,sDAAsD;IACtD,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,gDAAgD;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sEAAsE;IACtE,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,mFAAmF;IACnF,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;CACrC,CAAC;AAEF,2EAA2E;AAC3E,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAkMlC,wFAAwF;AACxF,wBAAsB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAuTzE;AAED,sEAAsE;AACtE,eAAO,MAAM,uBAAuB,wiBAC8f,CAAC;AAEniB,mEAAmE;AACnE,eAAO,MAAM,yBAAyB;;;CAIrC,CAAC"}
@@ -94,6 +94,18 @@ export declare function reciprocalRankFusion<T>(lists: Array<{
94
94
  item: T;
95
95
  score: number;
96
96
  }>;
97
+ /**
98
+ * Score candidates by exact query term overlap.
99
+ *
100
+ * Returns items sorted by number of exact term matches (descending).
101
+ * Used as an additional RRF list to boost results that contain query terms
102
+ * verbatim — important for proper nouns, file names, and technical terms
103
+ * that BM25's prefix matching + Porter stemming can miss or dilute.
104
+ *
105
+ * Terms are filtered through the standard stopword + single-char filter
106
+ * (same as `ftsQuery`), then matched case-insensitively via `includes()`.
107
+ */
108
+ export declare function exactTermMatchRank<T>(items: T[], getText: (item: T) => string, query: string): T[];
97
109
  import type { LLMClient } from "./types";
98
110
  /**
99
111
  * Expand a user query into multiple search variants using the configured LLM.
@@ -109,5 +121,5 @@ import type { LLMClient } from "./types";
109
121
  export declare function expandQuery(llm: LLMClient, query: string, model?: {
110
122
  providerID: string;
111
123
  modelID: string;
112
- }): Promise<string[]>;
124
+ }, sessionID?: string): Promise<string[]>;
113
125
  //# sourceMappingURL=search.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/search.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,SAAS,EAAE,WAAW,CAAC,MAAM,CAmGxC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,WAAW,SAAO,CAAC;AAEhC;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CASjD;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI5C;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI9C;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM,EAAE,CAelE;AAMD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,MAAM,CAMR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,KAAK,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAA;CAAE,CAAC,EACtD,CAAC,SAAK,GACL,KAAK,CAAC;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAkBnC;AAQD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC9C,OAAO,CAAC,MAAM,EAAE,CAAC,CAqCnB"}
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/search.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,SAAS,EAAE,WAAW,CAAC,MAAM,CAmGxC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,WAAW,SAAO,CAAC;AAEhC;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CASjD;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI5C;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI9C;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,SAAK,GAAG,MAAM,EAAE,CAelE;AAMD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,GACd,MAAM,CAMR;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,KAAK,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,CAAC,EAAE,CAAC;IAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAA;CAAE,CAAC,EACtD,CAAC,SAAK,GACL,KAAK,CAAC;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAkBnC;AAMD;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAClC,KAAK,EAAE,CAAC,EAAE,EACV,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,EAC5B,KAAK,EAAE,MAAM,GACZ,CAAC,EAAE,CAcL;AAQD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEzC;;;;;;;;;;GAUG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,MAAM,EACb,KAAK,CAAC,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAC/C,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,EAAE,CAAC,CAqCnB"}
@@ -170,7 +170,7 @@ export interface LLMClient {
170
170
  *
171
171
  * @param system System prompt text
172
172
  * @param user User message text
173
- * @param opts Optional model selection and worker identification
173
+ * @param opts Optional model selection, worker identification, and thinking control
174
174
  * @returns The assistant's text response, or null on failure
175
175
  */
176
176
  prompt(system: string, user: string, opts?: {
@@ -184,6 +184,46 @@ export interface LLMClient {
184
184
  * (e.g. OpenCode uses this as the session agent name).
185
185
  */
186
186
  workerID?: string;
187
+ /**
188
+ * Disable extended thinking/reasoning for this call.
189
+ *
190
+ * Background workers discard thinking tokens — they only extract the
191
+ * text response. Setting `thinking: false` tells the adapter to avoid
192
+ * producing (and billing for) thinking tokens when possible.
193
+ *
194
+ * Adapter behavior:
195
+ * - Gateway: no-op (bare API call never triggers thinking)
196
+ * - Pi: passes `thinkingEnabled: false` to `complete()`
197
+ * - OpenCode: cannot honor — SDK has no thinking toggle on session.prompt();
198
+ * relies on Part A (non-reasoning model selection) instead
199
+ */
200
+ thinking?: boolean;
201
+ /**
202
+ * When true, the request must be processed immediately and the result
203
+ * returned before the next user turn. When false or absent, the request
204
+ * may be deferred to a batch queue for cost savings (50% discount via
205
+ * Anthropic's Message Batches API).
206
+ *
207
+ * Callers that `await` the result for a blocking operation (compaction,
208
+ * overflow recovery, query expansion) should set `urgent: true`.
209
+ * Fire-and-forget background work (incremental distillation, idle
210
+ * curation) should leave it unset or set `false`.
211
+ *
212
+ * Only the gateway's BatchLLMClient honors this flag; other adapters
213
+ * (OpenCode, Pi) ignore it and always process immediately.
214
+ */
215
+ urgent?: boolean;
216
+ /**
217
+ * Session identifier for per-session auth credential lookup.
218
+ *
219
+ * The gateway uses this to resolve the correct API key or OAuth
220
+ * token for the session that triggered the work, preventing
221
+ * cross-session key mixups when multiple clients are connected.
222
+ *
223
+ * Other adapters (OpenCode, Pi) ignore this field — they resolve
224
+ * auth through their own mechanisms.
225
+ */
226
+ sessionID?: string;
187
227
  }): Promise<string | null>;
188
228
  }
189
229
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
@@ -22,6 +22,8 @@ export type ModelInfo = {
22
22
  input: {
23
23
  text: boolean;
24
24
  };
25
+ /** Whether this model supports extended thinking/reasoning. */
26
+ reasoning?: boolean;
25
27
  };
26
28
  };
27
29
  /** Result of a worker model validation stored in kv_meta. */
@@ -54,6 +56,8 @@ export declare function selectWorkerCandidates(sessionModel: {
54
56
  export declare function computeModelFingerprint(providerID: string, sessionModelID: string, activeModelIDs: string[]): string;
55
57
  export declare function getValidatedWorkerModel(providerID: string): WorkerModelResult | null;
56
58
  export declare function storeValidatedWorkerModel(result: WorkerModelResult): void;
59
+ /** Clear a stored worker model validation (e.g. when the model is deprecated). */
60
+ export declare function clearValidatedWorkerModel(providerID: string): void;
57
61
  /**
58
62
  * Check whether the stored validation is stale (fingerprint mismatch).
59
63
  */
@@ -73,6 +77,24 @@ export declare const WORKER_JUDGE_SYSTEM = "You are evaluating distillation qual
73
77
  export declare function workerJudgeUser(reference: string, candidate: string): string;
74
78
  /** Parse the judge's score from a response. Returns null on parse failure. */
75
79
  export declare function parseJudgeScore(response: string): number | null;
80
+ import type { LLMClient } from "./types";
81
+ export type ValidationInput = {
82
+ llm: LLMClient;
83
+ providerID: string;
84
+ sessionModelID: string;
85
+ candidates: ModelInfo[];
86
+ /** Recent gen-0 distillation to use as reference (observations text). */
87
+ referenceObservations: string;
88
+ /** Source messages text for re-running distillation with candidates. */
89
+ sourceMessagesText: string;
90
+ /** Date string for the distillation prompt. */
91
+ date: string;
92
+ };
93
+ /**
94
+ * Run the two-phase quality validation for worker model candidates.
95
+ * Returns the cheapest passing candidate, or null if none pass.
96
+ */
97
+ export declare function runValidation(input: ValidationInput): Promise<WorkerModelResult | null>;
76
98
  /**
77
99
  * Resolve the effective worker model for a given provider.
78
100
  * Priority: explicit config > validated auto-selection > session model (fallback).
@@ -1 +1 @@
1
- {"version":3,"file":"worker-model.d.ts","sourceRoot":"","sources":["../../src/worker-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH,0EAA0E;AAC1E,MAAM,MAAM,SAAS,GAAG;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE;QAAE,KAAK,EAAE;YAAE,IAAI,EAAE,OAAO,CAAA;SAAE,CAAA;KAAE,CAAC;CAC5C,CAAC;AAEF,6DAA6D;AAC7D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B,CAAC;AAQF;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,YAAY,EAAE;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EACzE,cAAc,EAAE,SAAS,EAAE,GAC1B,SAAS,EAAE,CAoCb;AAMD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,EAClB,cAAc,EAAE,MAAM,EACtB,cAAc,EAAE,MAAM,EAAE,GACvB,MAAM,CAKR;AAMD,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,MAAM,GACjB,iBAAiB,GAAG,IAAI,CAU1B;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI,CAQzE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,iBAAiB,GAAG,IAAI,EAChC,kBAAkB,EAAE,MAAM,GACzB,OAAO,CAGT;AAMD,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,OAAO,CAAC;IAChB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,qBAAqB,EAAE,MAAM,GAAG,IAAI,EACpC,qBAAqB,EAAE,MAAM,GAC5B,qBAAqB,CAsCvB;AAMD,eAAO,MAAM,mBAAmB,ijBASQ,CAAC;AAEzC,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,MAAM,CAER;AAED,8EAA8E;AAC9E,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI/D;AAMD;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,iBAAiB,CAAC,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,EAC3D,WAAW,CAAC,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAYrD"}
1
+ {"version":3,"file":"worker-model.d.ts","sourceRoot":"","sources":["../../src/worker-model.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@loreai/core",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
4
4
  "type": "module",
5
- "license": "MIT",
5
+ "license": "FSL-1.1-Apache-2.0",
6
6
  "description": "Shared memory engine for Lore — three-tier storage, distillation, gradient context management",
7
7
  "main": "./dist/node/index.js",
8
8
  "types": "./dist/node/index.d.ts",
@@ -23,6 +23,7 @@
23
23
  "build": "bun run script/build.ts"
24
24
  },
25
25
  "dependencies": {
26
+ "fastembed": "^2.1.0",
26
27
  "remark": "^15.0.1",
27
28
  "uuidv7": "^1.1.0",
28
29
  "zod": "^4.3.6"
@@ -9,7 +9,7 @@
9
9
  */
10
10
 
11
11
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
12
- import { dirname } from "path";
12
+ import { dirname, join } from "path";
13
13
  import * as ltm from "./ltm";
14
14
  import { serialize, inline, h, ul, liph, strong, t, root, unescapeMarkdown } from "./markdown";
15
15
 
@@ -34,6 +34,16 @@ const ALL_START_MARKERS = [
34
34
  "<!-- This section is auto-maintained by lore (https://github.com/BYK/opencode-lore) -->",
35
35
  ] as const;
36
36
 
37
+ /**
38
+ * Filename for the dedicated lore knowledge file. Always at the project root.
39
+ * Unlike the agents file (AGENTS.md / CLAUDE.md), this file is entirely owned
40
+ * by lore — no section markers needed, no non-lore content to preserve.
41
+ */
42
+ export const LORE_FILE = ".lore.md";
43
+
44
+ const LORE_FILE_HEADER =
45
+ "<!-- Managed by lore (https://github.com/BYK/loreai) — manual edits are imported on next session. -->";
46
+
37
47
  /** Regex matching a valid UUID (v4 or v7) — 8-4-4-4-12 hex groups. */
38
48
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
39
49
 
@@ -270,16 +280,25 @@ function buildSection(projectPath: string): string {
270
280
  // ---------------------------------------------------------------------------
271
281
 
272
282
  /**
273
- * Write current knowledge entries into the AGENTS.md file, preserving all
274
- * non-lore content. Creates the file if it doesn't exist.
283
+ * Write a pointer to `.lore.md` inside the agents file (AGENTS.md / CLAUDE.md),
284
+ * preserving all non-lore content. Also writes `.lore.md` with the actual
285
+ * knowledge entries as a side effect.
275
286
  */
276
287
  export function exportToFile(input: {
277
288
  projectPath: string;
278
289
  filePath: string;
279
290
  }): void {
280
- const sectionBody = buildSection(input.projectPath);
291
+ // Write the actual entries to .lore.md first.
292
+ exportLoreFile(input.projectPath);
293
+
294
+ // Build a pointer section for the agents file instead of full entries.
295
+ const pointerBody =
296
+ "\n## Long-term Knowledge\n\n" +
297
+ "For long-term knowledge entries managed by [lore](https://github.com/BYK/loreai) " +
298
+ "(gotchas, patterns, decisions, architecture), see [`.lore.md`](.lore.md) " +
299
+ "in the project root.\n";
281
300
  const newSection =
282
- LORE_SECTION_START + sectionBody + LORE_SECTION_END + "\n";
301
+ LORE_SECTION_START + pointerBody + LORE_SECTION_END + "\n";
283
302
 
284
303
  let fileContent = "";
285
304
  if (existsSync(input.filePath)) {
@@ -329,11 +348,11 @@ export function shouldImport(input: {
329
348
  }
330
349
 
331
350
  // ---------------------------------------------------------------------------
332
- // Import
351
+ // Import helpers
333
352
  // ---------------------------------------------------------------------------
334
353
 
335
354
  /**
336
- * Import knowledge entries from the agents file into the local DB.
355
+ * Upsert parsed entries into the local DB.
337
356
  *
338
357
  * Behaviour per entry:
339
358
  * - Known UUID (already in DB) → update content if it changed (manual edit)
@@ -341,26 +360,13 @@ export function shouldImport(input: {
341
360
  * - No UUID (hand-written) → create with a new UUIDv7
342
361
  * - Duplicate UUID in same file → first occurrence wins, rest ignored
343
362
  */
344
- export function importFromFile(input: {
345
- projectPath: string;
346
- filePath: string;
347
- }): void {
348
- if (!existsSync(input.filePath)) return;
349
-
350
- const fileContent = readFileSync(input.filePath, "utf8");
351
- const { section, before } = splitFile(fileContent);
352
-
353
- // Determine what to parse:
354
- // - If lore markers exist: parse ONLY the lore section body (avoid re-importing our own output)
355
- // - If no markers: parse the full file (first-time hand-written AGENTS.md import)
356
- const textToParse = section ?? fileContent;
357
-
358
- const fileEntries = parseEntriesFromSection(textToParse);
359
- if (!fileEntries.length) return;
360
-
363
+ function _importEntries(
364
+ entries: ParsedFileEntry[],
365
+ projectPath: string,
366
+ ): void {
361
367
  const seenIds = new Set<string>();
362
368
 
363
- for (const entry of fileEntries) {
369
+ for (const entry of entries) {
364
370
  if (entry.id !== null) {
365
371
  // Deduplicate: if same UUID appears twice in file, first wins
366
372
  if (seenIds.has(entry.id)) continue;
@@ -375,7 +381,7 @@ export function importFromFile(input: {
375
381
  } else {
376
382
  // Unknown UUID — entry came from another machine, preserve its ID
377
383
  ltm.create({
378
- projectPath: input.projectPath,
384
+ projectPath,
379
385
  category: entry.category,
380
386
  title: entry.title,
381
387
  content: entry.content,
@@ -387,13 +393,13 @@ export function importFromFile(input: {
387
393
  } else {
388
394
  // Hand-written entry — create with a new UUIDv7
389
395
  // Check for a near-duplicate by title to avoid double-import on re-runs
390
- const existing = ltm.forProject(input.projectPath, true);
396
+ const existing = ltm.forProject(projectPath, true);
391
397
  const titleMatch = existing.find(
392
398
  (e) => e.title.toLowerCase() === entry.title.toLowerCase(),
393
399
  );
394
400
  if (!titleMatch) {
395
401
  ltm.create({
396
- projectPath: input.projectPath,
402
+ projectPath,
397
403
  category: entry.category,
398
404
  title: entry.title,
399
405
  content: entry.content,
@@ -404,3 +410,80 @@ export function importFromFile(input: {
404
410
  }
405
411
  }
406
412
  }
413
+
414
+ // ---------------------------------------------------------------------------
415
+ // Import from agents file (AGENTS.md / CLAUDE.md)
416
+ // ---------------------------------------------------------------------------
417
+
418
+ /**
419
+ * Import knowledge entries from the agents file into the local DB.
420
+ * Used for backward compatibility when `.lore.md` doesn't exist yet.
421
+ */
422
+ export function importFromFile(input: {
423
+ projectPath: string;
424
+ filePath: string;
425
+ }): void {
426
+ if (!existsSync(input.filePath)) return;
427
+
428
+ const fileContent = readFileSync(input.filePath, "utf8");
429
+ const { section } = splitFile(fileContent);
430
+
431
+ // Determine what to parse:
432
+ // - If lore markers exist: parse ONLY the lore section body (avoid re-importing our own output)
433
+ // - If no markers: parse the full file (first-time hand-written AGENTS.md import)
434
+ const textToParse = section ?? fileContent;
435
+
436
+ const fileEntries = parseEntriesFromSection(textToParse);
437
+ if (!fileEntries.length) return;
438
+
439
+ _importEntries(fileEntries, input.projectPath);
440
+ }
441
+
442
+ // ---------------------------------------------------------------------------
443
+ // .lore.md — dedicated knowledge file
444
+ // ---------------------------------------------------------------------------
445
+
446
+ /**
447
+ * Returns true if a `.lore.md` file exists in the project root.
448
+ */
449
+ export function loreFileExists(projectPath: string): boolean {
450
+ return existsSync(join(projectPath, LORE_FILE));
451
+ }
452
+
453
+ /**
454
+ * Export current knowledge entries to `.lore.md` in the project root.
455
+ * The entire file is lore-owned — no section markers, no content to preserve.
456
+ */
457
+ export function exportLoreFile(projectPath: string): void {
458
+ const sectionBody = buildSection(projectPath);
459
+ const content = LORE_FILE_HEADER + "\n" + sectionBody;
460
+ writeFileSync(join(projectPath, LORE_FILE), content, "utf8");
461
+ }
462
+
463
+ /**
464
+ * Returns true if `.lore.md` needs to be imported:
465
+ * - File exists and its content differs from what lore would currently produce
466
+ */
467
+ export function shouldImportLoreFile(projectPath: string): boolean {
468
+ const fp = join(projectPath, LORE_FILE);
469
+ if (!existsSync(fp)) return false;
470
+
471
+ const fileContent = readFileSync(fp, "utf8");
472
+ const expected = LORE_FILE_HEADER + "\n" + buildSection(projectPath);
473
+ return hashSection(fileContent) !== hashSection(expected);
474
+ }
475
+
476
+ /**
477
+ * Import knowledge entries from `.lore.md` into the local DB.
478
+ * Parses the full file content (no section markers to split on).
479
+ */
480
+ export function importLoreFile(projectPath: string): void {
481
+ const fp = join(projectPath, LORE_FILE);
482
+ if (!existsSync(fp)) return;
483
+
484
+ const fileContent = readFileSync(fp, "utf8");
485
+ const fileEntries = parseEntriesFromSection(fileContent);
486
+ if (!fileEntries.length) return;
487
+
488
+ _importEntries(fileEntries, projectPath);
489
+ }
package/src/config.ts CHANGED
@@ -50,11 +50,15 @@ export const LoreConfig = z.object({
50
50
  * Anthropic's April 23 postmortem identified dropping reasoning blocks as
51
51
  * the root cause of forgetfulness/repetition.
52
52
  *
53
- * `idleResumeMinutes` is the threshold in minutes. Default 60 — matches
54
- * Anthropic's extended-cache eviction window, conservative across providers.
53
+ * `idleResumeMinutes` is the threshold in minutes. Default 5 — matches
54
+ * Anthropic's default-tier prompt cache TTL. After 5 min of inactivity the
55
+ * upstream cache is cold, so preserving byte-identity wastes cache-write cost
56
+ * for no benefit. Refreshing the caches on resume produces a better-fitting
57
+ * window at the same cold-write price. Users on Anthropic's extended-cache
58
+ * tier (1 h TTL) should set this to 60 in `.lore.json`.
55
59
  * Set to 0 to disable the feature.
56
60
  */
57
- idleResumeMinutes: z.number().min(0).max(24 * 60).default(60),
61
+ idleResumeMinutes: z.number().min(0).max(24 * 60).default(5),
58
62
  distillation: z
59
63
  .object({
60
64
  minMessages: z.number().min(3).default(5),
@@ -116,37 +120,40 @@ export const LoreConfig = z.object({
116
120
  * before search, improving recall for ambiguous queries. */
117
121
  queryExpansion: z.boolean().default(false),
118
122
  /** Vector embedding search.
119
- * Supports multiple providers: "voyage" (Voyage AI, VOYAGE_API_KEY),
120
- * "openai" (OpenAI, OPENAI_API_KEY).
121
- * Automatically enabled when the configured provider's API key env var is set.
122
- * Set enabled: false to explicitly disable even with the key present. */
123
+ * Supports multiple providers:
124
+ * - "local" (default): fastembed + ONNX Runtime, no API key needed.
125
+ * Uses bge-small-en-v1.5 (384 dims). Model downloaded on first use (~33MB),
126
+ * cached in ~/.cache/fastembed. ~150ms per query embed.
127
+ * - "voyage": Voyage AI (VOYAGE_API_KEY, voyage-code-3, 1024 dims)
128
+ * - "openai": OpenAI (OPENAI_API_KEY, text-embedding-3-small, 1536 dims)
129
+ * Set enabled: false to explicitly disable even with a provider available. */
123
130
  embeddings: z
124
131
  .object({
125
132
  /** Enable/disable vector embedding search. Default: true.
126
- * Set to false to explicitly disable even when the API key is set. */
133
+ * Set to false to explicitly disable. */
127
134
  enabled: z.boolean().default(true),
128
- /** Embedding provider. Default: "voyage".
129
- * Each provider reads its own env var for the API key:
135
+ /** Embedding provider. Default: "local".
136
+ * - "local": fastembed + ONNX Runtime, no API key (default model: bge-small-en-v1.5, 384 dims)
130
137
  * - "voyage": VOYAGE_API_KEY (default model: voyage-code-3, 1024 dims)
131
138
  * - "openai": OPENAI_API_KEY (default model: text-embedding-3-small, 1536 dims) */
132
- provider: z.enum(["voyage", "openai"]).default("voyage"),
139
+ provider: z.enum(["local", "voyage", "openai"]).default("local"),
133
140
  /** Model ID for the embedding provider. Default depends on provider. */
134
- model: z.string().default("voyage-code-3"),
135
- /** Embedding dimensions. Default: 1024. */
136
- dimensions: z.number().min(256).max(2048).default(1024),
141
+ model: z.string().default("BGESmallENV15"),
142
+ /** Embedding dimensions. Default: 384 (local) / 1024 (voyage) / 1536 (openai). */
143
+ dimensions: z.number().min(64).max(2048).default(384),
137
144
  })
138
145
  .default({
139
146
  enabled: true,
140
- provider: "voyage",
141
- model: "voyage-code-3",
142
- dimensions: 1024,
147
+ provider: "local",
148
+ model: "BGESmallENV15",
149
+ dimensions: 384,
143
150
  }),
144
151
  })
145
152
  .default({
146
153
  ftsWeights: { title: 6.0, content: 2.0, category: 3.0 },
147
154
  recallLimit: 10,
148
155
  queryExpansion: false,
149
- embeddings: { enabled: true, provider: "voyage" as const, model: "voyage-code-3", dimensions: 1024 },
156
+ embeddings: { enabled: true, provider: "local" as const, model: "BGESmallENV15", dimensions: 384 },
150
157
  }),
151
158
  crossProject: z.boolean().default(false),
152
159
  agentsFile: z
package/src/curator.ts CHANGED
@@ -82,7 +82,7 @@ export async function run(input: {
82
82
  const responseText = await input.llm.prompt(
83
83
  CURATOR_SYSTEM,
84
84
  userContent,
85
- { model, workerID: "lore-curator" },
85
+ { model, workerID: "lore-curator", thinking: false, sessionID: input.sessionID },
86
86
  );
87
87
  if (!responseText) return { created: 0, updated: 0, deleted: 0 };
88
88
 
@@ -185,7 +185,7 @@ export async function consolidate(input: {
185
185
  const responseText = await input.llm.prompt(
186
186
  CONSOLIDATION_SYSTEM,
187
187
  userContent,
188
- { model, workerID: "lore-curator" },
188
+ { model, workerID: "lore-curator", thinking: false, sessionID: input.sessionID },
189
189
  );
190
190
  if (!responseText) return { updated: 0, deleted: 0 };
191
191
 
package/src/db.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import { Database } from "#db/driver";
2
2
  import { join, dirname } from "path";
3
3
  import { mkdirSync } from "fs";
4
+ import { homedir } from "os";
4
5
 
5
- const SCHEMA_VERSION = 11;
6
+ const SCHEMA_VERSION = 12;
6
7
 
7
8
  const MIGRATIONS: string[] = [
8
9
  `
@@ -333,11 +334,27 @@ const MIGRATIONS: string[] = [
333
334
  WHERE content LIKE '%' || char(10) || '[tool:%'
334
335
  OR content LIKE '%' || char(10) || '[reasoning] %';
335
336
  `,
337
+ `
338
+ -- Version 12: Context health diagnostic columns on distillations.
339
+ --
340
+ -- r_compression: k/√N where k = distilled token count, N = source token
341
+ -- count. Values < 1.0 signal likely lossy compression. NULL for rows
342
+ -- created before this migration or for meta-distillations (gen > 0)
343
+ -- where the metric is not computed.
344
+ --
345
+ -- c_norm: normalized variance of relative-existence weights over source
346
+ -- message timestamps. Range [0, 1]; 0 = uniform distribution, 1 = attention
347
+ -- dominated by distant past. NULL for pre-migration rows or meta-distillations.
348
+ --
349
+ -- Both columns are nullable REALs — cheap to add, no backfill needed.
350
+ ALTER TABLE distillations ADD COLUMN r_compression REAL;
351
+ ALTER TABLE distillations ADD COLUMN c_norm REAL;
352
+ `,
336
353
  ];
337
354
 
338
355
  function dataDir() {
339
356
  const xdg = process.env.XDG_DATA_HOME;
340
- const base = xdg || join(process.env.HOME || "~", ".local", "share");
357
+ const base = xdg || join(homedir(), ".local", "share");
341
358
  return join(base, "opencode-lore");
342
359
  }
343
360