renor-engine 0.0.0-stage → 1.0.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 (176) hide show
  1. package/LICENSE +661 -0
  2. package/NOTICE +73 -0
  3. package/README.md +105 -2
  4. package/dist/BUILD.json +6 -0
  5. package/dist/api/apiAuth.js +43 -0
  6. package/dist/api/server.js +172 -0
  7. package/dist/buildIdentity.js +132 -0
  8. package/dist/cli-extractors.js +46 -0
  9. package/dist/cli.js +491 -0
  10. package/dist/config.js +65 -0
  11. package/dist/context/composer.js +320 -0
  12. package/dist/context/readHonesty.js +478 -0
  13. package/dist/context/rowStore.js +238 -0
  14. package/dist/conversation/formatter.js +81 -0
  15. package/dist/conversation/parser.js +189 -0
  16. package/dist/conversation/types.js +2 -0
  17. package/dist/conversation/writer.js +42 -0
  18. package/dist/db/client.js +147 -0
  19. package/dist/db/indexSalvage.js +81 -0
  20. package/dist/db/migrations.js +642 -0
  21. package/dist/db/readCache.js +109 -0
  22. package/dist/db/schema.js +5 -0
  23. package/dist/db/statements.js +89 -0
  24. package/dist/digests/digestCache.js +142 -0
  25. package/dist/digests/digests.js +597 -0
  26. package/dist/digests/worker.js +348 -0
  27. package/dist/embeddings/caching.js +337 -0
  28. package/dist/embeddings/coalescing.js +177 -0
  29. package/dist/embeddings/interactive.js +103 -0
  30. package/dist/embeddings/local.js +68 -0
  31. package/dist/embeddings/openai.js +105 -0
  32. package/dist/embeddings/rebuild.js +166 -0
  33. package/dist/embeddings/simdScan.js +258 -0
  34. package/dist/embeddings/space.js +21 -0
  35. package/dist/embeddings/types.js +14 -0
  36. package/dist/embeddings/vectorIndex.js +675 -0
  37. package/dist/embeddings/vertex.js +224 -0
  38. package/dist/eval/artifacts.js +42 -0
  39. package/dist/eval/cacheReport.js +139 -0
  40. package/dist/eval/comparison.js +182 -0
  41. package/dist/eval/context700-candidate.js +145 -0
  42. package/dist/eval/evalCache.js +525 -0
  43. package/dist/eval/hashEmbedding.js +35 -0
  44. package/dist/eval/longmemeval.js +56 -0
  45. package/dist/eval/metrics.js +181 -0
  46. package/dist/eval/renorbenchBaseline.js +486 -0
  47. package/dist/eval/renorbenchDocuments.js +134 -0
  48. package/dist/eval/renorbenchProduct.js +182 -0
  49. package/dist/eval/runLedger.js +279 -0
  50. package/dist/eval/runManifest.js +479 -0
  51. package/dist/eval/scoring.js +197 -0
  52. package/dist/evidence/attach.js +267 -0
  53. package/dist/evidence/background.js +147 -0
  54. package/dist/evidence/evidenceCache.js +182 -0
  55. package/dist/evidence/gate.js +37 -0
  56. package/dist/evidence/keyPool.js +85 -0
  57. package/dist/evidence/ollamaChat.js +84 -0
  58. package/dist/evidence/optin.js +165 -0
  59. package/dist/evidence/options.js +130 -0
  60. package/dist/evidence/secondPass.js +456 -0
  61. package/dist/extraction/classifyCapture.js +34 -0
  62. package/dist/extraction/decision-model.js +174 -0
  63. package/dist/extraction/eventExtractor.js +113 -0
  64. package/dist/extraction/extractionClient.js +122 -0
  65. package/dist/extraction/factExtractor.js +46 -0
  66. package/dist/extraction/factsWritePath.js +179 -0
  67. package/dist/extraction/preferenceExtractor.js +153 -0
  68. package/dist/extraction/secretGuard.js +176 -0
  69. package/dist/extraction/secretScanner.js +665 -0
  70. package/dist/extraction/typedFacts.js +224 -0
  71. package/dist/extraction/writePathAdjudication.js +110 -0
  72. package/dist/importing/apply.js +644 -0
  73. package/dist/importing/bundle-write.js +80 -0
  74. package/dist/importing/cli.js +407 -0
  75. package/dist/importing/existing.js +49 -0
  76. package/dist/importing/facts.js +123 -0
  77. package/dist/importing/forgetImported.js +79 -0
  78. package/dist/importing/hosted.js +467 -0
  79. package/dist/importing/index.js +29 -0
  80. package/dist/importing/journalLog.js +96 -0
  81. package/dist/importing/markdown.js +98 -0
  82. package/dist/importing/plan.js +206 -0
  83. package/dist/importing/secretScreen.js +113 -0
  84. package/dist/importing/serialize.js +188 -0
  85. package/dist/importing/source.js +463 -0
  86. package/dist/importing/types.js +6 -0
  87. package/dist/indexer/chunker.js +319 -0
  88. package/dist/indexer/dailyEntries.js +63 -0
  89. package/dist/indexer/hasher.js +10 -0
  90. package/dist/indexer/laneRuns.js +48 -0
  91. package/dist/indexer/o200k.js +481 -0
  92. package/dist/indexer/o200k.json +8 -0
  93. package/dist/indexer/outsideRoot.js +77 -0
  94. package/dist/indexer/parser.js +167 -0
  95. package/dist/indexer/pipeline.js +1168 -0
  96. package/dist/indexer/staleness.js +201 -0
  97. package/dist/indexer/tokenizer.js +77 -0
  98. package/dist/indexer/walker.js +184 -0
  99. package/dist/mcp/hive.js +88 -0
  100. package/dist/mcp/requestErrors.js +47 -0
  101. package/dist/mcp/server.js +396 -0
  102. package/dist/memory/agentLease.js +43 -0
  103. package/dist/memory/confinedWrite.js +315 -0
  104. package/dist/memory/controls.js +73 -0
  105. package/dist/memory/dailyNote.js +265 -0
  106. package/dist/memory/durableAppend.js +57 -0
  107. package/dist/memory/factConflicts.js +203 -0
  108. package/dist/memory/factTerms.js +321 -0
  109. package/dist/memory/hiveNameHeader.cjs +10 -0
  110. package/dist/memory/inventory.js +55 -0
  111. package/dist/memory/invisibleText.js +20 -0
  112. package/dist/memory/lifecycle.js +1756 -0
  113. package/dist/memory/limits.js +13 -0
  114. package/dist/memory/requests.js +183 -0
  115. package/dist/memory/sourceName.js +200 -0
  116. package/dist/memory/whatsNew.js +158 -0
  117. package/dist/memory/writer.js +175 -0
  118. package/dist/memory/writerConflicts.js +85 -0
  119. package/dist/memorymap/memoryMap.js +1568 -0
  120. package/dist/memorymap/replacedJournal.js +58 -0
  121. package/dist/memorymap/replacements.js +405 -0
  122. package/dist/mvp/activity.js +86 -0
  123. package/dist/mvp/agentMemory.js +1744 -0
  124. package/dist/mvp/auth.js +531 -0
  125. package/dist/mvp/cli.js +73 -0
  126. package/dist/mvp/client-store.js +462 -0
  127. package/dist/mvp/compileCache.js +249 -0
  128. package/dist/mvp/compileSeed.js +27 -0
  129. package/dist/mvp/config.js +288 -0
  130. package/dist/mvp/connectionStatus.js +80 -0
  131. package/dist/mvp/contextRelevance.js +413 -0
  132. package/dist/mvp/engine.js +1065 -0
  133. package/dist/mvp/exportAll.js +359 -0
  134. package/dist/mvp/factLanePack.js +77 -0
  135. package/dist/mvp/factMarkers.js +49 -0
  136. package/dist/mvp/factsLane.js +203 -0
  137. package/dist/mvp/hiddenSpans.js +585 -0
  138. package/dist/mvp/history.js +413 -0
  139. package/dist/mvp/hitDates.js +31 -0
  140. package/dist/mvp/hitFloor.js +36 -0
  141. package/dist/mvp/identity.js +18 -0
  142. package/dist/mvp/idle.js +113 -0
  143. package/dist/mvp/memoryDir.js +98 -0
  144. package/dist/mvp/posthogMcp.js +210 -0
  145. package/dist/mvp/readScope.js +104 -0
  146. package/dist/mvp/readUsefulness.js +222 -0
  147. package/dist/mvp/sanitize.js +48 -0
  148. package/dist/mvp/schemaRejections.js +91 -0
  149. package/dist/mvp/scope.js +127 -0
  150. package/dist/mvp/server.js +2089 -0
  151. package/dist/mvp/serverCard.js +29 -0
  152. package/dist/mvp/storedSize.js +139 -0
  153. package/dist/mvp/telemetry.js +441 -0
  154. package/dist/retrieval/adviceLines.js +195 -0
  155. package/dist/retrieval/adviceQuestion.js +44 -0
  156. package/dist/retrieval/conversationShape.js +44 -0
  157. package/dist/retrieval/dailyEntryTime.js +55 -0
  158. package/dist/retrieval/entityLookup.js +113 -0
  159. package/dist/retrieval/factsFirst.js +188 -0
  160. package/dist/retrieval/keyword.js +84 -0
  161. package/dist/retrieval/ledgerEventTime.js +51 -0
  162. package/dist/retrieval/ledgerLiveness.js +83 -0
  163. package/dist/retrieval/ledgerPresentation.js +161 -0
  164. package/dist/retrieval/noteIdentity.js +57 -0
  165. package/dist/retrieval/orchestrator.js +1086 -0
  166. package/dist/retrieval/queryHelpers.js +142 -0
  167. package/dist/retrieval/questionSpan.js +475 -0
  168. package/dist/retrieval/readerEvents.js +690 -0
  169. package/dist/retrieval/readerLayout.js +503 -0
  170. package/dist/retrieval/relativeTimeHints.js +113 -0
  171. package/dist/retrieval/semantic.js +67 -0
  172. package/dist/router/routerCache.js +106 -0
  173. package/dist/router/sessionRouter.js +726 -0
  174. package/dist/toolRefusal.js +120 -0
  175. package/dist/watcher/watcher.js +75 -0
  176. package/package.json +120 -4
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.factHits = factHits;
7
+ exports.withFactHits = withFactHits;
8
+ exports.indexBehindLedger = indexBehindLedger;
9
+ exports.indexNotice = indexNotice;
10
+ const path_1 = __importDefault(require("path"));
11
+ const fs_1 = __importDefault(require("fs"));
12
+ const orchestrator_1 = require("../retrieval/orchestrator");
13
+ const statements_1 = require("../db/statements");
14
+ const agentMemory_1 = require("./agentMemory");
15
+ const lifecycle_1 = require("../memory/lifecycle");
16
+ const writerConflicts_1 = require("../memory/writerConflicts");
17
+ const factTerms_1 = require("../memory/factTerms");
18
+ const ledgerLiveness_1 = require("../retrieval/ledgerLiveness");
19
+ const ledgerPresentation_1 = require("../retrieval/ledgerPresentation");
20
+ const scope_1 = require("./scope");
21
+ const digests_1 = require("../digests/digests");
22
+ const sourceName_1 = require("../memory/sourceName");
23
+ /**
24
+ * The fact as the index shows it, so a hit reads the same before and after index_memory: the fact itself, never the
25
+ * markup of the ledger's record (its `## MEM_… · time` header and `- subject: …` lines are bookkeeping, and no read
26
+ * returns them). The event and its time are in the hit's heading path.
27
+ */
28
+ function factBlock(row) {
29
+ return (0, ledgerPresentation_1.factText)(row.subject, row.predicate, row.object);
30
+ }
31
+ /**
32
+ * One current fact as a hit. `score` is left at 0 here and set by `factHits`, which knows the share of the query's
33
+ * words the fact holds; a fact named by a caller instead (`withFactHits` `also`) was found by meaning rather than by
34
+ * those words, so it keeps 0 — the convention session-expand hits use.
35
+ */
36
+ function factHit(row, ledger, date, reader, conflict) {
37
+ const notePath = path_1.default.relative(path_1.default.resolve(ledger.memoryDir), (0, lifecycle_1.resolveLedgerPath)(ledger.memoryDir, ledger.ledgerRelPath));
38
+ return {
39
+ notePath,
40
+ headingPath: row.eventId ? `${row.eventId} · ${row.validFrom}` : `${row.subject} > ${row.predicate}`,
41
+ text: factBlock(row),
42
+ score: 0,
43
+ reason: 'fact',
44
+ ...(date ? { session_date: date(row.validFrom) } : {}),
45
+ // Who saved it, as get_context's facts show it: another agent's name, and untrusted for an import.
46
+ ...(0, sourceName_1.authorMarker)(row.author, reader),
47
+ // The values another writer replaced that stay open against it (memory/writerConflicts.ts), when there are any.
48
+ ...(conflict !== undefined ? { writerConflict: conflict } : {}),
49
+ };
50
+ }
51
+ /** Facts can be returned before the ledger is indexed. Bound their clock by the actual ledger write, once per read. */
52
+ function ledgerTimeBound(ledger) {
53
+ let read = false;
54
+ let modified;
55
+ return at => {
56
+ if (!read) {
57
+ read = true;
58
+ try {
59
+ modified = fs_1.default.statSync((0, lifecycle_1.resolveLedgerPath)(ledger.memoryDir, ledger.ledgerRelPath)).mtime.toISOString();
60
+ }
61
+ catch { /* No trusted write time: the fact stays undated. */ }
62
+ }
63
+ return (0, orchestrator_1.clampSessionDate)(at, modified);
64
+ };
65
+ }
66
+ /**
67
+ * Current facts that match `query`, as search hits.
68
+ *
69
+ * `all`: every query word must be among the fact's words (search_text, a keyword tool).
70
+ * `any`: one is enough, and more shared words rank higher (search_memory, a natural-language
71
+ * tool). Stop words only count when nothing else is left. Facts whose ledger event is in
72
+ * `exclude` (lowercased ids the index already returned) are skipped before the `limit`, so they
73
+ * never use up a slot. Scope follows the facts lane of get_context: omitted means every scope,
74
+ * a given scope means exactly that one.
75
+ */
76
+ function matchedFacts(db, args, terms) {
77
+ if (terms.length === 0)
78
+ return [];
79
+ const scope = args.scope === undefined ? undefined : (0, scope_1.normalizeScope)(args.scope);
80
+ const exclude = args.exclude ?? new Set();
81
+ // At most |exclude| of the best matches are dropped below, so this many always leaves `limit`.
82
+ return (0, factTerms_1.findCurrentFacts)(db, { terms: [...terms], scope, match: args.match, limit: args.limit + exclude.size })
83
+ .filter(row => !(row.eventId && exclude.has(row.eventId.toLowerCase())))
84
+ .slice(0, args.limit);
85
+ }
86
+ function factHits(db, ledger, args) {
87
+ const terms = (0, agentMemory_1.factQueryTerms)(args.query);
88
+ const date = args.dated ? ledgerTimeBound(ledger) : undefined;
89
+ return matchedFacts(db, args, terms)
90
+ .map(row => ({ ...factHit(row, ledger, date, args.reader), score: Math.round((row.shared / terms.length) * 100) / 100 }));
91
+ }
92
+ /**
93
+ * What a fact claims, in its own scope: two current facts with the same key are the same fact whatever ledger event
94
+ * backs them, and one derived from a note has none. So a fact already on the page is recognised without an event id
95
+ * to compare, which is the only way a fact saved through `remember` (not through `save_memory`) could be listed twice.
96
+ */
97
+ function factKey(row) {
98
+ return `${(0, scope_1.normalizeScope)(row.scope)}\u0000${row.subject}\u0000${row.predicate}`;
99
+ }
100
+ /**
101
+ * The index's hits plus the current facts that match `args.query`, at most `args.limit` hits in all (the search's
102
+ * top_k): the facts take the places the index's own hits leave, so no index hit is lost or reordered, and a full page
103
+ * of index hits gets no fact (they used to come on top of it, up to top_k more, matched by any word: live dogfood,
104
+ * 2026-10-03, D14). Fact hits go first, after a leading evidence summary if there is one, which is outside top_k as
105
+ * before. A fact whose ledger event the index already returned is not repeated.
106
+ *
107
+ * `also` are facts a caller names because it is about to report one of them as its closest match, so they are listed
108
+ * whether or not the query's words found them — the same rule get_context applies to the fact its verdict was judged on
109
+ * (agentMemory.ts `missed`). They go after the facts the words found, in the order given, and only out of the room top_k
110
+ * leaves: a page already full of index hits gets none of them, and a full room of facts the words found gives way to
111
+ * them. So the page never passes top_k, and the verdict keeps its match whenever the page can carry it. A fact already on
112
+ * the page is not repeated, by its ledger event or by the claim it makes in its own scope — a fact saved through
113
+ * `remember` has no event to compare.
114
+ */
115
+ function withFactHits(db, ledger, indexHits, args, also = []) {
116
+ const lead = (0, digests_1.leadingSummaryHits)(indexHits);
117
+ const room = args.limit - (indexHits.length - lead);
118
+ const listed = new Set(indexHits.flatMap(ledgerLiveness_1.ledgerEventIds));
119
+ const terms = (0, agentMemory_1.factQueryTerms)(args.query);
120
+ const words = room > 0 ? matchedFacts(db, { ...args, limit: room, exclude: listed }, terms) : [];
121
+ const claimed = new Set(words.map(factKey));
122
+ // The named facts the page does not hold yet, so each is listed once and none is pushed out by another.
123
+ const pending = [];
124
+ for (const row of also) {
125
+ const event = row.eventId?.toLowerCase();
126
+ if (claimed.has(factKey(row)) || (event !== undefined && listed.has(event)))
127
+ continue;
128
+ if (event !== undefined)
129
+ listed.add(event);
130
+ claimed.add(factKey(row));
131
+ pending.push(row);
132
+ }
133
+ // Only as many named facts as the page has room for; a page top_k has already filled takes none of them.
134
+ const named = pending.slice(0, Math.max(0, room));
135
+ const date = args.dated ? ledgerTimeBound(ledger) : undefined;
136
+ const disputes = (0, writerConflicts_1.writerConflictLines)(db, [...words, ...named].map(row => row.eventId));
137
+ const line = (row) => (row.eventId === null ? undefined : disputes.get(row.eventId));
138
+ const facts = [
139
+ ...words.slice(0, Math.max(0, room - named.length)).map(row => ({ ...factHit(row, ledger, date, args.reader, line(row)), score: Math.round((row.shared / terms.length) * 100) / 100 })),
140
+ ...named.map(row => factHit(row, ledger, date, args.reader, line(row))),
141
+ ];
142
+ return [...indexHits.slice(0, lead), ...facts, ...indexHits.slice(lead)];
143
+ }
144
+ /**
145
+ * Whether the newest saved fact is missing from the chunk index.
146
+ *
147
+ * The ledger is append-only and indexed whole, so the index holds a prefix of it: if the newest
148
+ * event is there, every older one is too. The facts table knows the newest event; the chunk
149
+ * full-text index finds its heading (the id, as the tokens `mem` and the rest) without reading the
150
+ * ledger's chunks.
151
+ *
152
+ * A read is told only about the events it can see (a scoped read returns the ledger events saved in
153
+ * its own scope, readScope.ts): a named scope or `global` by the newest event of that scope, a read
154
+ * without a scope by the newest event of all.
155
+ */
156
+ function indexBehindLedger(db, ledgerPath, scope) {
157
+ const newest = (0, factTerms_1.newestFactEvent)(db, scope);
158
+ if (!newest)
159
+ return false;
160
+ const phrase = `"${newest.replace(/"/g, '""').replace(/_/g, ' ')}"`;
161
+ const indexed = (0, statements_1.prepareOnce)(db, `SELECT 1 FROM chunks_fts JOIN chunks c ON c.id = chunks_fts.rowid
162
+ WHERE chunks_fts MATCH ? AND c.note_path = ? LIMIT 1`).get(phrase, ledgerPath);
163
+ return !indexed;
164
+ }
165
+ /** Added to a response only while the index is behind. Silence means no known lag. */
166
+ const INDEX_BEHIND = {
167
+ stale: true,
168
+ detail: 'The search index has not caught up with some saved facts, so they are matched by keyword only. Run index_memory to find them by meaning too.',
169
+ };
170
+ /**
171
+ * How many saved note files of the scope (every scope when none is given) are still waiting for their embedding. A
172
+ * note whose embedding failed or ran past the write budget keeps its chunks, which keyword search finds, and its file
173
+ * stays unfinished (note_hash ''); search by meaning cannot see it until a later pass embeds it. The partial index of
174
+ * migration 15 answers this at the cost of those few rows.
175
+ */
176
+ function unembeddedNoteCount(db, scope) {
177
+ const pred = scope === undefined ? null : (0, scope_1.scopeSqlPredicate)((0, scope_1.normalizeScope)(scope), 'path');
178
+ const sql = `SELECT COUNT(*) FROM notes WHERE note_hash = ''${pred ? ` AND ${pred.sql}` : ''}`;
179
+ return (0, statements_1.prepareOnce)(db, sql).pluck().get(...(pred?.params ?? []));
180
+ }
181
+ /**
182
+ * `{ index }` for a read that uses meaning-based search while the index is behind the ledger, or while notes of its
183
+ * scope wait for their embedding (`unembeddedNotes`: the count, and search_text or a retry finds them).
184
+ * `semantic` is whether an embedding provider is configured; without one there is no meaning
185
+ * search for index_memory to catch up. Silence means nothing is known to be behind or waiting.
186
+ */
187
+ function indexNotice(db, semantic, ledger, scope) {
188
+ if (!semantic)
189
+ return {};
190
+ const behind = indexBehindLedger(db, (0, lifecycle_1.resolveLedgerPath)(ledger.memoryDir, ledger.ledgerRelPath), scope === undefined ? undefined : (0, scope_1.normalizeScope)(scope));
191
+ const unembedded = unembeddedNoteCount(db, scope);
192
+ if (unembedded === 0)
193
+ return behind ? { index: INDEX_BEHIND } : {};
194
+ const it = unembedded === 1 ? 'it' : 'them';
195
+ const waiting = `${unembedded} saved note${unembedded === 1 ? ' is' : 's are'} still waiting for an embedding, so search_memory cannot find ${it} by meaning yet. search_text finds ${it} by exact words now; a retry finds ${it} once the embedder answers.`;
196
+ return {
197
+ index: {
198
+ stale: true,
199
+ detail: behind ? `${INDEX_BEHIND.detail} ${waiting}` : waiting,
200
+ unembeddedNotes: unembedded,
201
+ },
202
+ };
203
+ }