claude-memory-layer 1.0.22 → 1.0.24

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 (51) hide show
  1. package/.claude/settings.local.json +11 -0
  2. package/README.md +2 -0
  3. package/dist/cli/index.js +87 -17
  4. package/dist/cli/index.js.map +2 -2
  5. package/dist/core/index.js +30 -5
  6. package/dist/core/index.js.map +2 -2
  7. package/dist/hooks/post-tool-use.js +117 -18
  8. package/dist/hooks/post-tool-use.js.map +2 -2
  9. package/dist/hooks/semantic-daemon.js +7337 -0
  10. package/dist/hooks/semantic-daemon.js.map +7 -0
  11. package/dist/hooks/session-end.js +71 -16
  12. package/dist/hooks/session-end.js.map +2 -2
  13. package/dist/hooks/session-start.js +156 -24
  14. package/dist/hooks/session-start.js.map +4 -4
  15. package/dist/hooks/stop.js +101 -18
  16. package/dist/hooks/stop.js.map +2 -2
  17. package/dist/hooks/user-prompt-submit.js +291 -102
  18. package/dist/hooks/user-prompt-submit.js.map +4 -4
  19. package/dist/server/api/index.js +71 -16
  20. package/dist/server/api/index.js.map +2 -2
  21. package/dist/server/index.js +71 -16
  22. package/dist/server/index.js.map +2 -2
  23. package/dist/services/memory-service.js +71 -16
  24. package/dist/services/memory-service.js.map +2 -2
  25. package/dist/ui/app.js +48 -1
  26. package/dist/ui/index.html +11 -3
  27. package/memory/_index.md +1 -0
  28. package/memory/agent_response/uncategorized/2026-03-04.md +1138 -1
  29. package/memory/session_summary/uncategorized/2026-03-04.md +31 -0
  30. package/memory/tool_observation/uncategorized/2026-03-04.md +785 -1
  31. package/memory/user_prompt/uncategorized/2026-03-04.md +438 -1
  32. package/package.json +1 -1
  33. package/scripts/build.ts +2 -1
  34. package/specs/selective-tool-observation/context.md +100 -0
  35. package/specs/selective-tool-observation/plan.md +158 -0
  36. package/specs/selective-tool-observation/spec.md +127 -0
  37. package/src/cli/index.ts +1 -0
  38. package/src/core/embedder.ts +15 -4
  39. package/src/core/sqlite-event-store.ts +16 -0
  40. package/src/core/turn-state.ts +48 -0
  41. package/src/core/types.ts +1 -0
  42. package/src/hooks/post-tool-use.ts +47 -2
  43. package/src/hooks/semantic-daemon-client.ts +208 -0
  44. package/src/hooks/semantic-daemon.ts +276 -0
  45. package/src/hooks/session-start.ts +7 -0
  46. package/src/hooks/stop.ts +19 -4
  47. package/src/hooks/user-prompt-submit.ts +48 -40
  48. package/src/services/memory-service.ts +59 -16
  49. package/src/services/session-history-importer.ts +18 -0
  50. package/src/ui/app.js +48 -1
  51. package/src/ui/index.html +11 -3
@@ -1834,6 +1834,21 @@ var SQLiteEventStore = class {
1834
1834
  [id, eventId, sessionId, score, query.slice(0, 100)]
1835
1835
  );
1836
1836
  }
1837
+ /**
1838
+ * Get session IDs that have unevaluated retrievals (measured_at IS NULL).
1839
+ * Excludes the current session. Used to backfill sessions that ended without Stop hook.
1840
+ */
1841
+ async getUnevaluatedSessions(currentSessionId, limit = 5) {
1842
+ await this.initialize();
1843
+ const rows = sqliteAll(
1844
+ this.db,
1845
+ `SELECT DISTINCT session_id FROM memory_helpfulness
1846
+ WHERE measured_at IS NULL AND session_id != ?
1847
+ ORDER BY created_at DESC LIMIT ?`,
1848
+ [currentSessionId, limit]
1849
+ );
1850
+ return rows.map((r) => r.session_id);
1851
+ }
1837
1852
  /**
1838
1853
  * Evaluate helpfulness for all retrievals in a session
1839
1854
  * Called at session end - uses behavioral signals to compute score
@@ -2621,7 +2636,7 @@ var VectorStore = class {
2621
2636
 
2622
2637
  // src/core/embedder.ts
2623
2638
  import { pipeline } from "@huggingface/transformers";
2624
- var Embedder = class {
2639
+ var Embedder = class _Embedder {
2625
2640
  pipeline = null;
2626
2641
  modelName;
2627
2642
  activeModelName;
@@ -2652,6 +2667,11 @@ var Embedder = class {
2652
2667
  this.initialized = true;
2653
2668
  }
2654
2669
  }
2670
+ // ~4 chars per token; 512 tokens * 4 = 2048, use 2000 to be safe
2671
+ static MAX_CHARS = 2e3;
2672
+ truncate(text) {
2673
+ return text.length > _Embedder.MAX_CHARS ? text.slice(0, _Embedder.MAX_CHARS) : text;
2674
+ }
2655
2675
  /**
2656
2676
  * Generate embedding for a single text
2657
2677
  */
@@ -2660,9 +2680,11 @@ var Embedder = class {
2660
2680
  if (!this.pipeline) {
2661
2681
  throw new Error("Embedding pipeline not initialized");
2662
2682
  }
2663
- const output = await this.pipeline(text, {
2683
+ const output = await this.pipeline(this.truncate(text), {
2664
2684
  pooling: "mean",
2665
- normalize: true
2685
+ normalize: true,
2686
+ truncation: true,
2687
+ max_length: 512
2666
2688
  });
2667
2689
  const vector = Array.from(output.data);
2668
2690
  return {
@@ -2684,9 +2706,11 @@ var Embedder = class {
2684
2706
  for (let i = 0; i < texts.length; i += batchSize) {
2685
2707
  const batch = texts.slice(i, i + batchSize);
2686
2708
  for (const text of batch) {
2687
- const output = await this.pipeline(text, {
2709
+ const output = await this.pipeline(this.truncate(text), {
2688
2710
  pooling: "mean",
2689
- normalize: true
2711
+ normalize: true,
2712
+ truncation: true,
2713
+ max_length: 512
2690
2714
  });
2691
2715
  const vector = Array.from(output.data);
2692
2716
  results.push({
@@ -5956,6 +5980,7 @@ var MemoryService = class {
5956
5980
  projectPath = null;
5957
5981
  readOnly;
5958
5982
  lightweightMode;
5983
+ embeddingOnly;
5959
5984
  mdMirror;
5960
5985
  storagePath;
5961
5986
  constructor(config) {
@@ -5963,6 +5988,7 @@ var MemoryService = class {
5963
5988
  this.storagePath = storagePath;
5964
5989
  this.readOnly = config.readOnly ?? false;
5965
5990
  this.lightweightMode = config.lightweightMode ?? false;
5991
+ this.embeddingOnly = config.embeddingOnly ?? false;
5966
5992
  this.mdMirror = new MarkdownMirror2(process.cwd());
5967
5993
  if (!this.readOnly && !fs4.existsSync(storagePath)) {
5968
5994
  fs4.mkdirSync(storagePath, { recursive: true });
@@ -6036,19 +6062,21 @@ var MemoryService = class {
6036
6062
  this.embedder
6037
6063
  );
6038
6064
  this.vectorWorker.start();
6039
- this.retriever.setGraduationPipeline(this.graduation);
6040
- this.graduationWorker = createGraduationWorker(
6041
- this.sqliteStore,
6042
- this.graduation
6043
- );
6044
- this.graduationWorker.start();
6045
- if (this.analyticsStore) {
6046
- this.syncWorker = new SyncWorker(
6065
+ if (!this.embeddingOnly) {
6066
+ this.retriever.setGraduationPipeline(this.graduation);
6067
+ this.graduationWorker = createGraduationWorker(
6047
6068
  this.sqliteStore,
6048
- this.analyticsStore,
6049
- { intervalMs: 3e4, batchSize: 500 }
6069
+ this.graduation
6050
6070
  );
6051
- this.syncWorker.start();
6071
+ this.graduationWorker.start();
6072
+ if (this.analyticsStore) {
6073
+ this.syncWorker = new SyncWorker(
6074
+ this.sqliteStore,
6075
+ this.analyticsStore,
6076
+ { intervalMs: 3e4, batchSize: 500 }
6077
+ );
6078
+ this.syncWorker.start();
6079
+ }
6052
6080
  }
6053
6081
  const savedMode = await this.sqliteStore.getEndlessConfig("mode");
6054
6082
  if (savedMode === "endless") {
@@ -6772,6 +6800,19 @@ var MemoryService = class {
6772
6800
  await this.initialize();
6773
6801
  await this.sqliteStore.recordRetrieval(eventId, sessionId, score, query);
6774
6802
  }
6803
+ /**
6804
+ * Record a query-level retrieval trace (used by user-prompt-submit hook).
6805
+ * Feeds the retrieval_traces table that powers dashboard stats.
6806
+ */
6807
+ async recordQueryTrace(input) {
6808
+ await this.initialize();
6809
+ await this.sqliteStore.recordRetrievalTrace({
6810
+ ...input,
6811
+ candidateDetails: [],
6812
+ selectedDetails: [],
6813
+ fallbackTrace: []
6814
+ });
6815
+ }
6775
6816
  /**
6776
6817
  * Evaluate helpfulness of retrievals in a session (called at session end)
6777
6818
  */
@@ -6779,6 +6820,20 @@ var MemoryService = class {
6779
6820
  await this.initialize();
6780
6821
  await this.sqliteStore.evaluateSessionHelpfulness(sessionId);
6781
6822
  }
6823
+ /**
6824
+ * Backfill helpfulness evaluation for sessions that ended without Stop hook.
6825
+ * Call on first turn of a new session to catch missed evaluations.
6826
+ */
6827
+ async evaluatePendingSessions(currentSessionId) {
6828
+ await this.initialize();
6829
+ const sessions = await this.sqliteStore.getUnevaluatedSessions(currentSessionId, 5);
6830
+ for (const sid of sessions) {
6831
+ try {
6832
+ await this.sqliteStore.evaluateSessionHelpfulness(sid);
6833
+ } catch {
6834
+ }
6835
+ }
6836
+ }
6782
6837
  /**
6783
6838
  * Get most helpful memories ranked by helpfulness score
6784
6839
  */