nlm-memory 0.15.0 → 0.16.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nlm-memory",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Local-first non-linear memory operating system for AI operators.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nlm-memory",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "Local-first persistent memory for AI coding agents. Recalls relevant prior sessions on every prompt; learns which sessions actually get cited. Owner-edited timeline beats append-only memory layers.",
5
5
  "author": {
6
6
  "name": "Edward Chalupa",
@@ -64,8 +64,8 @@ function recordSurfaced(conversationId, ids) {
64
64
  }
65
65
 
66
66
  // src/core/hook/pointer-block.ts
67
- function formatPointerBlock(hits, facts = []) {
68
- if (hits.length === 0 && facts.length === 0) return "";
67
+ function formatPointerBlock(hits, facts = [], exemplars = []) {
68
+ if (hits.length === 0 && facts.length === 0 && exemplars.length === 0) return "";
69
69
  const out = [];
70
70
  if (hits.length > 0) {
71
71
  out.push("## Possibly-relevant prior sessions (nlm-memory)");
@@ -86,9 +86,16 @@ function formatPointerBlock(hits, facts = []) {
86
86
  out.push(`- ${f.subject} ${f.predicate}: ${f.value}${tag}`);
87
87
  }
88
88
  }
89
- out.push(
90
- "NLM tools: recall_sessions (search), get_session (full transcript), recall_facts (prior decisions), get_fact_history (how a decision evolved)."
91
- );
89
+ if (exemplars.length > 0) {
90
+ if (out.length > 0) out.push("");
91
+ out.push("## Related code exemplars (nlm-memory)");
92
+ for (const e of exemplars) {
93
+ const langPart = e.lang ? `${e.lang} \xB7 ` : "";
94
+ out.push(`- [${e.outcome}] ${langPart}${e.repo} - ${e.taskContext.slice(0, 120)}`);
95
+ }
96
+ }
97
+ const tools = exemplars.length > 0 ? "NLM tools: recall_sessions (search), get_session (full transcript), recall_facts (prior decisions), get_fact_history (how a decision evolved), recall_code (pull the full code for a related exemplar)." : "NLM tools: recall_sessions (search), get_session (full transcript), recall_facts (prior decisions), get_fact_history (how a decision evolved).";
98
+ out.push(tools);
92
99
  return out.join("\n");
93
100
  }
94
101
 
@@ -298,9 +305,9 @@ var RECALL_LIMIT = 5;
298
305
  var RECALL_TIMEOUT_MS = 2e3;
299
306
  async function recallOverHttp(prompt, runtime, conversationId) {
300
307
  const query = extractRecallQuery(prompt);
301
- if (query === null) return { hits: [], facts: [] };
308
+ if (query === null) return { hits: [], facts: [], exemplars: [] };
302
309
  const portValue = process.env["NLM_PORT"] ?? "3940";
303
- const url = `http://localhost:${portValue}/api/recall?q=${encodeURIComponent(query)}&mode=keyword&limit=${RECALL_LIMIT}&withFacts=true` + (conversationId ? `&conversation_id=${encodeURIComponent(conversationId)}` : "");
310
+ const url = `http://localhost:${portValue}/api/recall?q=${encodeURIComponent(query)}&mode=keyword&limit=${RECALL_LIMIT}&withFacts=true&withExemplars=true` + (conversationId ? `&conversation_id=${encodeURIComponent(conversationId)}` : "");
304
311
  const controller = new AbortController();
305
312
  const timer = setTimeout(() => controller.abort(), RECALL_TIMEOUT_MS);
306
313
  try {
@@ -310,12 +317,12 @@ async function recallOverHttp(prompt, runtime, conversationId) {
310
317
  headers: hookAuthHeaders(extra),
311
318
  signal: controller.signal
312
319
  });
313
- if (!res.ok) return { hits: [], facts: [] };
320
+ if (!res.ok) return { hits: [], facts: [], exemplars: [] };
314
321
  let body;
315
322
  try {
316
323
  body = await res.json();
317
324
  } catch {
318
- return { hits: [], facts: [] };
325
+ return { hits: [], facts: [], exemplars: [] };
319
326
  }
320
327
  const hits = (body.results ?? []).map((r) => ({
321
328
  id: r.id,
@@ -330,7 +337,13 @@ async function recallOverHttp(prompt, runtime, conversationId) {
330
337
  value: f.value,
331
338
  corroborationCount: f.corroborationCount
332
339
  }));
333
- return { hits, facts };
340
+ const exemplars = (body.relatedExemplars ?? []).map((e) => ({
341
+ outcome: e.outcome,
342
+ lang: e.lang,
343
+ repo: e.repo,
344
+ taskContext: e.taskContext
345
+ }));
346
+ return { hits, facts, exemplars };
334
347
  } finally {
335
348
  clearTimeout(timer);
336
349
  }
@@ -380,7 +393,7 @@ async function runHook(input, deps) {
380
393
  perFireCap: PER_FIRE_CAP,
381
394
  perConversationCap: PER_CONVERSATION_CAP
382
395
  });
383
- const block = formatPointerBlock(selected, fetched.facts);
396
+ const block = formatPointerBlock(selected, fetched.facts, fetched.exemplars);
384
397
  const estTokens = Math.ceil(block.length / 4);
385
398
  appendHookLog({
386
399
  ts: (/* @__PURE__ */ new Date()).toISOString(),
@@ -53,8 +53,8 @@ function recordSurfaced(conversationId, ids) {
53
53
  }
54
54
 
55
55
  // src/core/hook/pointer-block.ts
56
- function formatPointerBlock(hits, facts = []) {
57
- if (hits.length === 0 && facts.length === 0) return "";
56
+ function formatPointerBlock(hits, facts = [], exemplars = []) {
57
+ if (hits.length === 0 && facts.length === 0 && exemplars.length === 0) return "";
58
58
  const out = [];
59
59
  if (hits.length > 0) {
60
60
  out.push("## Possibly-relevant prior sessions (nlm-memory)");
@@ -75,9 +75,16 @@ function formatPointerBlock(hits, facts = []) {
75
75
  out.push(`- ${f.subject} ${f.predicate}: ${f.value}${tag}`);
76
76
  }
77
77
  }
78
- out.push(
79
- "NLM tools: recall_sessions (search), get_session (full transcript), recall_facts (prior decisions), get_fact_history (how a decision evolved)."
80
- );
78
+ if (exemplars.length > 0) {
79
+ if (out.length > 0) out.push("");
80
+ out.push("## Related code exemplars (nlm-memory)");
81
+ for (const e of exemplars) {
82
+ const langPart = e.lang ? `${e.lang} \xB7 ` : "";
83
+ out.push(`- [${e.outcome}] ${langPart}${e.repo} - ${e.taskContext.slice(0, 120)}`);
84
+ }
85
+ }
86
+ const tools = exemplars.length > 0 ? "NLM tools: recall_sessions (search), get_session (full transcript), recall_facts (prior decisions), get_fact_history (how a decision evolved), recall_code (pull the full code for a related exemplar)." : "NLM tools: recall_sessions (search), get_session (full transcript), recall_facts (prior decisions), get_fact_history (how a decision evolved).";
87
+ out.push(tools);
81
88
  return out.join("\n");
82
89
  }
83
90