clawmem 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.
- package/AGENTS.md +2 -0
- package/CLAUDE.md +2 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/mcp.ts +5 -1
- package/src/memory.ts +27 -3
package/AGENTS.md
CHANGED
|
@@ -461,6 +461,8 @@ Recency intent detected ("latest", "recent", "last session"):
|
|
|
461
461
|
compositeScore = (0.10 × searchScore + 0.70 × recencyScore + 0.20 × confidenceScore) × qualityMultiplier × coActivationBoost
|
|
462
462
|
```
|
|
463
463
|
|
|
464
|
+
**`query` tool (v0.13.0+):** for non-recency queries the `query` tool uses retrieval-tuned weights `0.70 × searchScore + 0.15 × recencyScore + 0.15 × confidenceScore` (from a held-out judged eval). Recency intent still switches to the `0.10 / 0.70 / 0.20` weights above. `search`, `vsearch`, `memory_retrieve`, and the context-surfacing hook keep the `0.50 / 0.25 / 0.25` default.
|
|
465
|
+
|
|
464
466
|
| Content Type | Half-Life | Effect |
|
|
465
467
|
|--------------|-----------|--------|
|
|
466
468
|
| decision, deductive, preference, hub | ∞ | Never decay |
|
package/CLAUDE.md
CHANGED
|
@@ -461,6 +461,8 @@ Recency intent detected ("latest", "recent", "last session"):
|
|
|
461
461
|
compositeScore = (0.10 × searchScore + 0.70 × recencyScore + 0.20 × confidenceScore) × qualityMultiplier × coActivationBoost
|
|
462
462
|
```
|
|
463
463
|
|
|
464
|
+
**`query` tool (v0.13.0+):** for non-recency queries the `query` tool uses retrieval-tuned weights `0.70 × searchScore + 0.15 × recencyScore + 0.15 × confidenceScore` (from a held-out judged eval). Recency intent still switches to the `0.10 / 0.70 / 0.20` weights above. `search`, `vsearch`, `memory_retrieve`, and the context-surfacing hook keep the `0.50 / 0.25 / 0.25` default.
|
|
465
|
+
|
|
464
466
|
| Content Type | Half-Life | Effect |
|
|
465
467
|
|--------------|-----------|--------|
|
|
466
468
|
| decision, deductive, preference, hub | ∞ | Never decay |
|
package/README.md
CHANGED
|
@@ -814,7 +814,7 @@ User Query + optional intent hint
|
|
|
814
814
|
→ Intent-Aware Chunk Selection (intent terms at 0.5× weight alongside query terms at 1.0×)
|
|
815
815
|
→ Cross-Encoder Reranking (4000 char context; intent prepended; chunk dedup; batch cap=4)
|
|
816
816
|
→ Rerank/RRF Blend (blendRerank: 0.9·reranker + 0.1·normalized-RRF tiebreaker; reranker can promote over RRF #1; falls back to RRF order if reranker unavailable)
|
|
817
|
-
→
|
|
817
|
+
→ Composite Scoring (query-tuned: (search × 0.70 + recency × 0.15 + confidence × 0.15) × qualityMultiplier × lengthNorm × coActivationBoost + pinBoost; recency-intent queries → 0.10/0.70/0.20; other tools keep the 0.50/0.25/0.25 default)
|
|
818
818
|
→ MMR Diversity Filter (Jaccard bigram similarity > 0.6 → demoted)
|
|
819
819
|
→ Ranked Results
|
|
820
820
|
```
|
package/package.json
CHANGED
package/src/mcp.ts
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
import {
|
|
29
29
|
applyCompositeScoring,
|
|
30
30
|
hasRecencyIntent,
|
|
31
|
+
QUERY_WEIGHTS,
|
|
31
32
|
type EnrichedResult,
|
|
32
33
|
type CoActivationFn,
|
|
33
34
|
} from "./memory.ts";
|
|
@@ -807,7 +808,10 @@ This is the recommended entry point for ALL memory queries.`,
|
|
|
807
808
|
|
|
808
809
|
const coFn = (path: string) => store.getCoActivated(path);
|
|
809
810
|
const enriched = enrichResults(store, searchResults, query);
|
|
810
|
-
|
|
811
|
+
// Phase B (§11.12): the `query` tool's hybrid+rerank pipeline uses QUERY_WEIGHTS (search 0.70) —
|
|
812
|
+
// the eval-validated re-weight. Recency intent still wins RECENCY_WEIGHTS by construction
|
|
813
|
+
// (applyCompositeScoring ignores options.weights when hasRecencyIntent(query) and !forceWeights).
|
|
814
|
+
let scored = applyCompositeScoring(enriched, query, coFn, { weights: QUERY_WEIGHTS })
|
|
811
815
|
.filter(r => r.compositeScore >= (minScore || 0));
|
|
812
816
|
if (diverse !== false) scored = applyMMRDiversity(scored);
|
|
813
817
|
scored = scored.slice(0, limit || 10);
|
package/src/memory.ts
CHANGED
|
@@ -185,6 +185,15 @@ export type CompositeWeights = {
|
|
|
185
185
|
|
|
186
186
|
export const DEFAULT_WEIGHTS: CompositeWeights = { search: 0.5, recency: 0.25, confidence: 0.25 };
|
|
187
187
|
export const RECENCY_WEIGHTS: CompositeWeights = { search: 0.1, recency: 0.7, confidence: 0.2 };
|
|
188
|
+
// Query-tool retrieval weights (Phase B, 2026-06-25). A held-out judged eval (n=199, GLM-5.2 judge,
|
|
189
|
+
// quadratic-weighted κ=0.681 vs an independent annotator) showed the default 0.50 search weight
|
|
190
|
+
// under-weights topical relevance for a work-memory vault: w_search 0.70 lifts graded NDCG@10 by +0.064
|
|
191
|
+
// (paired permutation p<1e-4, robust across precision/exploratory/temporal families) with ZERO freshness regression —
|
|
192
|
+
// the newest-correct doc is never demoted in the supersession guard (demotionRate 0), whereas 0.80
|
|
193
|
+
// demotes it out of the top-10 in 2/19 cases. Applied ONLY by the `query` tool's full hybrid+rerank
|
|
194
|
+
// pipeline (the path the eval mirrored). NOT applied under recency intent — RECENCY_WEIGHTS wins by
|
|
195
|
+
// construction in applyCompositeScoring. See BLEND-COMPOSITE-REBALANCE-DESIGN.md §11.12.
|
|
196
|
+
export const QUERY_WEIGHTS: CompositeWeights = { search: 0.7, recency: 0.15, confidence: 0.15 };
|
|
188
197
|
|
|
189
198
|
const RECENCY_PATTERNS = [
|
|
190
199
|
/\brecent(ly)?\b/i,
|
|
@@ -274,13 +283,28 @@ function canonicalMemoryMultiplier(path: string, contentType: string, query: str
|
|
|
274
283
|
return 1.0;
|
|
275
284
|
}
|
|
276
285
|
|
|
286
|
+
export type CompositeScoringOptions = {
|
|
287
|
+
/** Query-scoped weights override. Replaces DEFAULT_WEIGHTS; NOT applied under recency intent unless forceWeights. */
|
|
288
|
+
weights?: CompositeWeights;
|
|
289
|
+
/** Injected clock for deterministic scoring (tests/eval). Defaults to new Date(). */
|
|
290
|
+
now?: Date;
|
|
291
|
+
/** Test/experiment only: apply `weights` even under recency intent (bypass the RECENCY_WEIGHTS switch). */
|
|
292
|
+
forceWeights?: boolean;
|
|
293
|
+
};
|
|
294
|
+
|
|
277
295
|
export function applyCompositeScoring(
|
|
278
296
|
results: EnrichedResult[],
|
|
279
297
|
query: string,
|
|
280
|
-
coActivationFn?: CoActivationFn
|
|
298
|
+
coActivationFn?: CoActivationFn,
|
|
299
|
+
options?: CompositeScoringOptions
|
|
281
300
|
): ScoredResult[] {
|
|
282
|
-
const
|
|
283
|
-
|
|
301
|
+
const recencyIntent = hasRecencyIntent(query);
|
|
302
|
+
// Recency intent keeps RECENCY_WEIGHTS (production contract) unless forceWeights overrides (experiments).
|
|
303
|
+
// A query-scoped `weights` override otherwise replaces DEFAULT_WEIGHTS; absent options => exact prior behavior.
|
|
304
|
+
const weights = (recencyIntent && !options?.forceWeights)
|
|
305
|
+
? RECENCY_WEIGHTS
|
|
306
|
+
: (options?.weights ?? (recencyIntent ? RECENCY_WEIGHTS : DEFAULT_WEIGHTS));
|
|
307
|
+
const now = options?.now ?? new Date();
|
|
284
308
|
|
|
285
309
|
const scored = results.map(r => {
|
|
286
310
|
const recency = recencyScore(r.modifiedAt, r.contentType, now, r.accessCount, r.lastAccessedAt);
|