dsh-companion-memory-core 0.1.0 → 0.1.1

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/README.md CHANGED
@@ -21,6 +21,13 @@ through the host's slot service; note browsing stays on the tool surface. A
21
21
  custom pane is deferred: host remote namespaces are Typert-generated, so a
22
22
  third-party plugin cannot register a new RPC group at runtime.
23
23
 
24
+ When consolidation runs, the model route is borrowed from the current session
25
+ request header. Set `reviewProvider` / `reviewModel` in the profile config to
26
+ pin a specific one; leaving both empty follows whatever the conversation uses.
27
+ Every written note carries an `evidence` quote that is verified verbatim
28
+ against the input actually shown to the model — fabricated quotes are dropped
29
+ before they reach disk.
30
+
24
31
  The host exposes no `learning` / `contentMode` / `toolVerified` admission
25
32
  metadata, so unverified `tool/result` output is deliberately never archived.
26
33
  User and assistant messages are the only long-term sources in v0.
@@ -11,6 +11,10 @@ const NOTE_TYPES = ['user', 'feedback', 'project', 'reference'];
11
11
  function operationMarker(body) {
12
12
  return /<!-- op: ([a-f0-9]+) -->/.exec(body)?.[1];
13
13
  }
14
+ /** Whitespace/case-tolerant containment so verbatim quotes survive line wrapping. */
15
+ function normalizeQuote(text) {
16
+ return text.replace(/\s+/g, ' ').trim().toLowerCase();
17
+ }
14
18
  function parseNotes(text) {
15
19
  const start = text.indexOf('{');
16
20
  const end = text.lastIndexOf('}');
@@ -67,17 +71,20 @@ export class LlmReviewer {
67
71
  return empty;
68
72
  const budget = this.options.contextTokens ?? 800;
69
73
  const lines = [];
70
- let used = 0;
74
+ const usedCandidates = [];
75
+ let spent = 0;
71
76
  for (const item of batch) {
72
77
  const line = `[${item.role}] ${item.content.slice(0, 800)}`;
73
78
  const cost = estimateTokens(line);
74
- if (used + cost > budget)
79
+ if (spent + cost > budget)
75
80
  break;
76
81
  lines.push(line);
77
- used += cost;
82
+ usedCandidates.push(item);
83
+ spent += cost;
78
84
  }
79
85
  if (lines.length === 0)
80
86
  return empty;
87
+ const haystack = normalizeQuote(lines.join('\n'));
81
88
  let answer;
82
89
  try {
83
90
  answer = (await this.adapter.complete({
@@ -101,6 +108,20 @@ export class LlmReviewer {
101
108
  const written = [];
102
109
  const today = new Date().toISOString().slice(0, 10);
103
110
  for (const note of parsed) {
111
+ // Verbatim gate: an evidence quote the model was never shown (or garbled)
112
+ // must never reach disk.
113
+ const evidenceNorm = normalizeQuote(note.evidence);
114
+ if (!haystack.includes(evidenceNorm))
115
+ continue;
116
+ const sourceRefs = usedCandidates
117
+ .filter((item) => normalizeQuote(`[${item.role}] ${item.content.slice(0, 800)}`)
118
+ .includes(evidenceNorm))
119
+ .map((item) => item.id)
120
+ .slice(0, 4);
121
+ // A quote spanning two adjacent lines still passes the haystack check;
122
+ // attribute it to the batch window instead of inventing a source.
123
+ if (sourceRefs.length === 0)
124
+ sourceRefs.push(usedCandidates[0].id);
104
125
  const payloadHash = createHash('sha256').update(JSON.stringify(note)).digest('hex');
105
126
  const opId = operationId(companionId, batch[0].id, batch[0].seq, payloadHash);
106
127
  if (seen.has(opId))
@@ -113,7 +134,7 @@ export class LlmReviewer {
113
134
  created: today,
114
135
  updated: today,
115
136
  evidence: note.evidence,
116
- sourceRefs: batch.slice(0, 4).map((item) => item.id),
137
+ sourceRefs,
117
138
  supersededBy: null,
118
139
  confidence: 0.7,
119
140
  strength: 0.6,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-companion-memory-core",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Local, host-independent long-term memory core for DeepSeek Harness: plain-text notes, a bounded index, and auditable evidence.",
5
5
  "type": "module",
6
6
  "license": "MIT",