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,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EvalHashEmbeddingProvider = void 0;
4
+ /**
5
+ * Deterministic lexical hash embeddings for eval infrastructure smoke tests.
6
+ *
7
+ * This provider intentionally has no semantic-quality claim. It exists so CI can
8
+ * execute indexing/vector-search/scoring paths without network/model downloads.
9
+ * Any manifest using it must be marked qualityEligible=false.
10
+ */
11
+ class EvalHashEmbeddingProvider {
12
+ dimensions = 256;
13
+ identity = { kind: 'eval-hash', model: 'lexical-hash-v1' };
14
+ vector(text) {
15
+ const out = new Array(this.dimensions).fill(0);
16
+ const words = text.toLowerCase().match(/[\p{L}\p{N}]+/gu) ?? [];
17
+ for (const word of words) {
18
+ let hash = 2166136261;
19
+ for (let i = 0; i < word.length; i++) {
20
+ hash ^= word.charCodeAt(i);
21
+ hash = Math.imul(hash, 16777619);
22
+ }
23
+ out[(hash >>> 0) % this.dimensions] += 1;
24
+ }
25
+ const norm = Math.sqrt(out.reduce((sum, value) => sum + value * value, 0)) || 1;
26
+ return out.map(value => value / norm);
27
+ }
28
+ async embed(texts) {
29
+ return texts.map(text => this.vector(text));
30
+ }
31
+ async embedQuery(text) {
32
+ return this.vector(text);
33
+ }
34
+ }
35
+ exports.EvalHashEmbeddingProvider = EvalHashEmbeddingProvider;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseTimestamp = parseTimestamp;
4
+ exports.validateLongMemRows = validateLongMemRows;
5
+ /** Upstream timestamps have no zone. Interpret them as UTC, never host-local time. */
6
+ function parseTimestamp(value) {
7
+ const official = /^(\d{4})\/(\d{2})\/(\d{2})(?: \([A-Za-z]{3}\))?(?: (\d{2}):(\d{2}))?$/.exec(value);
8
+ const iso = official ? `${official[1]}-${official[2]}-${official[3]}T${official[4] ?? '00'}:${official[5] ?? '00'}:00Z` : value;
9
+ if (!/(Z|[+-]\d{2}:\d{2})$/.test(iso))
10
+ throw new Error(`Ambiguous timestamp: ${value}`);
11
+ const date = new Date(iso);
12
+ if (Number.isNaN(date.getTime()) || (official && date.toISOString().slice(0, 16) !== iso.slice(0, 16)))
13
+ throw new Error(`Invalid timestamp: ${value}`);
14
+ return date;
15
+ }
16
+ function uniqueStrings(values, label) {
17
+ if (!Array.isArray(values) || values.some(v => typeof v !== 'string' || !v.trim()))
18
+ throw new Error(`Invalid ${label}`);
19
+ if (new Set(values).size !== values.length)
20
+ throw new Error(`Duplicate ${label}`);
21
+ }
22
+ function validateLongMemRows(rows) {
23
+ if (!Array.isArray(rows) || !rows.length)
24
+ throw new Error('Empty/invalid LongMemEval dataset');
25
+ uniqueStrings(rows.map(r => r.question_id), 'question id');
26
+ for (const row of rows) {
27
+ if (!row.question?.trim() || !row.question_type?.trim())
28
+ throw new Error('Missing question/type');
29
+ parseTimestamp(row.question_date);
30
+ uniqueStrings(row.answer_session_ids, 'answer session id');
31
+ // Official data may repeat a noise haystack session id; a repeated ANSWER id
32
+ // would make evidence mapping ambiguous and stays rejected.
33
+ const seenAnswer = new Set(row.answer_session_ids);
34
+ const haystackCounts = new Map();
35
+ for (const id of row.haystack_session_ids) {
36
+ haystackCounts.set(id, (haystackCounts.get(id) ?? 0) + 1);
37
+ if ((haystackCounts.get(id) ?? 0) > 1 && seenAnswer.has(id)) {
38
+ throw new Error(`Duplicated answer session id in haystack: ${id}`);
39
+ }
40
+ }
41
+ if (!Array.isArray(row.haystack_sessions) || !Array.isArray(row.haystack_dates)
42
+ || row.haystack_sessions.length !== row.haystack_session_ids.length
43
+ || row.haystack_dates.length !== row.haystack_session_ids.length)
44
+ throw new Error('Haystack arrays differ in length');
45
+ row.haystack_dates.forEach(parseTimestamp);
46
+ // Official data legitimately contains empty noise sessions; roles/content stay strict.
47
+ for (const turns of row.haystack_sessions) {
48
+ if (!Array.isArray(turns) || turns.some(t => !['user', 'assistant'].includes(t.role) || typeof t.content !== 'string')) {
49
+ throw new Error('Invalid session turns');
50
+ }
51
+ }
52
+ if (!row.question_id.endsWith('_abs') && (!row.answer_session_ids.length
53
+ || row.answer_session_ids.some(id => !row.haystack_session_ids.includes(id))))
54
+ throw new Error('Missing answer evidence sessions');
55
+ }
56
+ }
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.roleOf = roleOf;
4
+ exports.hitMatchesTarget = hitMatchesTarget;
5
+ exports.matchedTargetIndexes = matchedTargetIndexes;
6
+ exports.hitAtK = hitAtK;
7
+ exports.recallAtK = recallAtK;
8
+ exports.recallAllAtK = recallAllAtK;
9
+ exports.forbiddenRetrieved = forbiddenRetrieved;
10
+ exports.reciprocalRank = reciprocalRank;
11
+ exports.ndcgAtK = ndcgAtK;
12
+ exports.contradictionFirst = contradictionFirst;
13
+ /**
14
+ * Role resolution for a gold target.
15
+ *
16
+ * Explicit `role` always wins. Otherwise RenorBench v0 semantics apply:
17
+ * - relevance >= 2 -> positive (creditable for Hit/Recall/MRR and nDCG)
18
+ * - relevance === 1 -> forbidden (superseded/contradictory value that is NOT
19
+ * the answer to the query; never creditable, and surfacing it first is an
20
+ * error tracked by contradictionFirst)
21
+ * - relevance absent -> positive (the target is the only/primary gold)
22
+ *
23
+ * Use explicit `role: 'supporting'` when a low-grade target is genuinely
24
+ * acceptable evidence (nDCG-graded but never counted by binary metrics).
25
+ */
26
+ function roleOf(target) {
27
+ if (target.role)
28
+ return target.role;
29
+ if (target.relevance === undefined)
30
+ return 'positive';
31
+ return target.relevance >= 2 ? 'positive' : 'forbidden';
32
+ }
33
+ function normalized(value) {
34
+ return (value ?? '').trim().toLowerCase();
35
+ }
36
+ /**
37
+ * Matching semantics:
38
+ *
39
+ * - Path-pinned targets (notePath set) require the hit to come from exactly
40
+ * that note, and credit a needle occurring in the hit text or in the pinned
41
+ * path itself (session-id style metadata matching, used by LongMemEval).
42
+ * - Text-scoped targets (no notePath) match against the retrieved text ONLY.
43
+ * A needle appearing merely in a filename never earns textual relevance
44
+ * credit, and unrelated notes can never satisfy the target.
45
+ */
46
+ function hitMatchesTarget(hit, target) {
47
+ const needle = normalized(target.match);
48
+ if (!needle)
49
+ return false;
50
+ if (target.notePath !== undefined) {
51
+ if (normalized(hit.notePath) !== normalized(target.notePath))
52
+ return false;
53
+ return normalized(hit.text).includes(needle) || normalized(target.notePath).includes(needle);
54
+ }
55
+ return normalized(hit.text).includes(needle);
56
+ }
57
+ function creditableTargets(targets) {
58
+ return targets.filter(target => roleOf(target) === 'positive');
59
+ }
60
+ function matchedTargetIndexes(hits, targets, k) {
61
+ const matched = new Set();
62
+ for (const hit of hits.slice(0, k)) {
63
+ targets.forEach((target, index) => {
64
+ if (hitMatchesTarget(hit, target))
65
+ matched.add(index);
66
+ });
67
+ }
68
+ return matched;
69
+ }
70
+ /**
71
+ * Binary Hit@K: credit only positive evidence. Stale/forbidden or merely
72
+ * supporting gold targets can never produce a Hit.
73
+ */
74
+ function hitAtK(hits, targets, k) {
75
+ const positive = creditableTargets(targets);
76
+ if (positive.length === 0)
77
+ return 0;
78
+ return matchedTargetIndexes(hits, positive, k).size > 0 ? 1 : 0;
79
+ }
80
+ /**
81
+ * Recall@K over positive evidence only.
82
+ */
83
+ function recallAtK(hits, targets, k) {
84
+ const positive = creditableTargets(targets);
85
+ if (positive.length === 0)
86
+ return 0;
87
+ return matchedTargetIndexes(hits, positive, k).size / positive.length;
88
+ }
89
+ /**
90
+ * All-required-evidence retrieval (multi-hop): 1 only when every required
91
+ * target is matched within top-K. Single-target lists reduce to Hit@K.
92
+ */
93
+ function recallAllAtK(hits, targets, k) {
94
+ const positive = creditableTargets(targets);
95
+ if (positive.length === 0)
96
+ return 0;
97
+ return matchedTargetIndexes(hits, positive, k).size === positive.length ? 1 : 0;
98
+ }
99
+ /**
100
+ * True when any forbidden-evidence target is retrieved within top-K.
101
+ * Used for deletion/erasure cases: retrieving deleted or must-not-surface
102
+ * content is a violation regardless of ordering.
103
+ */
104
+ function forbiddenRetrieved(hits, targets, k) {
105
+ const forbidden = targets.filter(target => roleOf(target) === 'forbidden');
106
+ if (forbidden.length === 0)
107
+ return false;
108
+ return matchedTargetIndexes(hits, forbidden, k).size > 0;
109
+ }
110
+ /**
111
+ * Reciprocal rank of the first positive-evidence hit.
112
+ */
113
+ function reciprocalRank(hits, targets) {
114
+ const positive = creditableTargets(targets);
115
+ if (positive.length === 0)
116
+ return 0;
117
+ const rank = hits.findIndex(hit => positive.some(target => hitMatchesTarget(hit, target)));
118
+ return rank === -1 ? 0 : 1 / (rank + 1);
119
+ }
120
+ function dcg(relevances) {
121
+ return relevances.reduce((sum, relevance, index) => {
122
+ if (relevance <= 0)
123
+ return sum;
124
+ return sum + (Math.pow(2, relevance) - 1) / Math.log2(index + 2);
125
+ }, 0);
126
+ }
127
+ /**
128
+ * Graded nDCG where each gold target can receive credit at most once.
129
+ * This prevents duplicated retrieval rows from inflating the score.
130
+ * Forbidden targets are excluded entirely; supporting targets keep their grade.
131
+ */
132
+ function ndcgAtK(hits, targets, k) {
133
+ const graded = targets
134
+ .map((target, index) => ({ target, index }))
135
+ .filter(({ target }) => roleOf(target) !== 'forbidden');
136
+ if (graded.length === 0)
137
+ return 0;
138
+ const credited = new Set();
139
+ const observed = [];
140
+ for (const hit of hits.slice(0, k)) {
141
+ let bestIndex = -1;
142
+ let bestRelevance = 0;
143
+ graded.forEach(({ target, index }) => {
144
+ if (credited.has(index) || !hitMatchesTarget(hit, target))
145
+ return;
146
+ const relevance = target.relevance ?? 1;
147
+ if (relevance > bestRelevance) {
148
+ bestRelevance = relevance;
149
+ bestIndex = index;
150
+ }
151
+ });
152
+ if (bestIndex >= 0)
153
+ credited.add(bestIndex);
154
+ observed.push(bestRelevance);
155
+ }
156
+ const ideal = graded
157
+ .map(({ target }) => target.relevance ?? 1)
158
+ .sort((a, b) => b - a)
159
+ .slice(0, k);
160
+ const idealDcg = dcg(ideal);
161
+ return idealDcg === 0 ? 0 : dcg(observed) / idealDcg;
162
+ }
163
+ /**
164
+ * True when the highest-ranked gold-matching hit matches only forbidden
165
+ * targets: an obsolete/contradictory answer was surfaced ahead of the
166
+ * current one. Cases without both positive and forbidden targets never
167
+ * trigger this.
168
+ */
169
+ function contradictionFirst(hits, targets) {
170
+ const hasPositive = targets.some(target => roleOf(target) === 'positive');
171
+ const hasForbidden = targets.some(target => roleOf(target) === 'forbidden');
172
+ if (!hasPositive || !hasForbidden)
173
+ return false;
174
+ for (const hit of hits) {
175
+ const matched = targets.filter(target => hitMatchesTarget(hit, target));
176
+ if (matched.length === 0)
177
+ continue;
178
+ return matched.every(target => roleOf(target) === 'forbidden');
179
+ }
180
+ return false;
181
+ }