claude-memory-layer 1.0.45 → 1.0.47

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.
@@ -2572,6 +2572,7 @@ var VectorOutbox = class {
2572
2572
  // src/core/retrieval-debug-lanes.ts
2573
2573
  var RETRIEVAL_DEBUG_LANE_NAMES = [
2574
2574
  "raw_event",
2575
+ "session_event",
2575
2576
  "session_summary",
2576
2577
  "graph_path",
2577
2578
  "facet_match"
@@ -8448,6 +8449,18 @@ var COMMAND_ARTIFACT_PATTERNS = [
8448
8449
  /<local-command-stdout>[\s\S]*?<\/local-command-stdout>/i,
8449
8450
  /<local-command-stderr>[\s\S]*?<\/local-command-stderr>/i
8450
8451
  ];
8452
+ var LOW_SIGNAL_CONTEXT_PATTERNS = [
8453
+ /<environment_context\b[\s\S]*<\/environment_context>/i,
8454
+ /<turn_aborted>/i,
8455
+ /^#\s*AGENTS\.md\s+instructions\b[\s\S]*<INSTRUCTIONS>/i,
8456
+ /^\s*(?:understood[,\s.]*)?(?:stopping|stopped|pausing|paused)\s+here\b[\s\S]{0,180}\blet\s+me\s+know\s+when\s+you(?:'d|\s+would)?\s+like\s+to\s+continue\b/i,
8457
+ /^\s*\[?CONTEXT\s+COMPACTION\s*[—-]\s*REFERENCE\s+ONLY\]?\b[\s\S]{0,600}\b(?:earlier\s+turns\s+were\s+compacted|handoff\s+from\s+a\s+previous\s+context\s+window|active\s+task)\b/i,
8458
+ /^\s*Summary\s+generation\s+was\s+unavailable\.\s*\d+\s+message\(s\)\s+were\s+removed\s+to\s+free\s+context\s+space\b/i,
8459
+ /^\s*---\s*END\s+OF\s+CONTEXT\s+SUMMARY\b/i,
8460
+ /^\s*\[Your\s+active\s+task\s+list\s+was\s+preserved\s+across\s+context\s+compression\]/i,
8461
+ /^➜\s+\S+\s+git:\([^)]*\)\s+/i,
8462
+ /^\$\s+\S+/i
8463
+ ];
8451
8464
  var CONTINUATION_QUERY_PATTERNS = [
8452
8465
  /^\s*(?:continue|resume|next|what(?:'s| is)? next|next\s+(?:step|task|action)|recommended\s+(?:next\s+)?(?:step|task|action)|what should (?:we|i) do next)\??\s*$/i,
8453
8466
  /^\s*(?:응\s*)?(?:이어서(?:\s*진행(?:해줘)?)?|계속(?:\s*해줘)?|다음\s*(?:단계|작업|추천\s*작업|추천|할\s*일)?(?:은|는)?(?:\s*(?:뭐야|진행(?:해줘)?))?\??|남은\s*(?:추가(?:로)?\s*)?(?:(?:할\s*만한\s*)?(?:작업|일)|할\s*일)?(?:은|는)?\s*(?:있어|있나|있나요|뭐야)\??|추천\s*작업(?:은|는)?(?:\s*뭐야)?\??|진행해줘)\s*$/i
@@ -8459,7 +8472,7 @@ var SHORT_REPAIR_FOLLOW_UP_PATTERNS = [
8459
8472
  var CURRENT_STATE_QUERY_PATTERNS = [
8460
8473
  /\bcurrent\b.*\b(?:state|status|deployment|blocker|pr|pull request)\b/i,
8461
8474
  /\b(?:still|as current|current)\b.*\b(?:unresolved|open|pending|not completed)\b/i,
8462
- /\b(?:old|obsolete|stale|resolved|already resolved)\b.*\b(?:current|still|unresolved|open|state|status)\b/i,
8475
+ /\b(?:old|obsolete|stale|resolved|already resolved)\b.*\b(?:current|still|unresolved|open|status)\b/i,
8463
8476
  /(?:현재|아직|이전|오래된|해결된).*(?:상태|미해결|열린|블로커|PR|풀리퀘스트)/i
8464
8477
  ];
8465
8478
  var STALE_CONTENT_PATTERNS = [
@@ -8605,6 +8618,21 @@ function isCommandArtifactQuery(query) {
8605
8618
  if (normalized.includes("command-name") || normalized.includes("command-message")) return true;
8606
8619
  return COMMAND_ARTIFACT_PATTERNS.some((pattern) => pattern.test(trimmed));
8607
8620
  }
8621
+ function isCommandArtifactContent(content) {
8622
+ const trimmed = content.trim();
8623
+ if (!trimmed) return false;
8624
+ const normalized = trimmed.toLowerCase();
8625
+ if (normalized.includes("local-command-stdout") || normalized.includes("local-command-stderr")) return true;
8626
+ if (normalized.includes("command-name") || normalized.includes("command-message")) return true;
8627
+ return COMMAND_ARTIFACT_PATTERNS.some((pattern) => pattern.test(trimmed));
8628
+ }
8629
+ function isLowSignalContextContent(content) {
8630
+ const trimmed = content.trim();
8631
+ if (!trimmed) return true;
8632
+ if (isCommandArtifactContent(trimmed)) return true;
8633
+ if (LOW_SIGNAL_CONTEXT_PATTERNS.some((pattern) => pattern.test(trimmed))) return true;
8634
+ return false;
8635
+ }
8608
8636
  function isGenericContinuationQuery(query) {
8609
8637
  const trimmed = query.trim();
8610
8638
  if (!trimmed) return false;
@@ -8622,6 +8650,16 @@ function isShortRepairFollowUpQuery(query) {
8622
8650
  if (tokens.length > 8) return false;
8623
8651
  return SHORT_REPAIR_FOLLOW_UP_PATTERNS.some((pattern) => pattern.test(trimmed));
8624
8652
  }
8653
+ function isLowConfidenceContextFallbackQuery(query) {
8654
+ const trimmed = query.trim();
8655
+ if (!trimmed) return false;
8656
+ if (isGenericContinuationQuery(trimmed) || isShortRepairFollowUpQuery(trimmed)) return true;
8657
+ const terms = new Set(tokenizeQualityText(trimmed));
8658
+ if ((terms.has("compacted") || terms.has("compaction")) && terms.has("handoff")) return false;
8659
+ const hasContinuationRecall = /^(?:continue|resume)\b/i.test(trimmed) && (terms.has("work") || terms.has("step") || terms.has("task") || terms.has("last") || terms.has("completed"));
8660
+ const hasValidationGateRecall = terms.has("validation") && (terms.has("gate") || terms.has("check")) && (terms.has("run") || terms.has("before") || terms.has("commit") || terms.has("committing") || terms.has("change"));
8661
+ return hasContinuationRecall || hasValidationGateRecall;
8662
+ }
8625
8663
  function isCurrentStateQuery(query) {
8626
8664
  const trimmed = query.trim();
8627
8665
  if (!trimmed) return false;
@@ -8795,6 +8833,7 @@ var Retriever = class {
8795
8833
  }
8796
8834
  async retrieve(query, options = {}) {
8797
8835
  const opts = { ...DEFAULT_OPTIONS, ...options };
8836
+ const retrievalMode = options.retrievalMode ?? ((options.strategy ?? DEFAULT_OPTIONS.strategy) === "auto" ? "session-event-hybrid" : "event");
8798
8837
  const sessionFilter = opts.scope?.sessionId ?? opts.sessionId;
8799
8838
  const fallbackTrace = [];
8800
8839
  const qualityQuery = buildRetrievalQualityQuery(query);
@@ -8825,6 +8864,7 @@ var Retriever = class {
8825
8864
  decayPolicy: opts.decayPolicy,
8826
8865
  intentRewrite: opts.intentRewrite === true,
8827
8866
  graphHop: opts.graphHop,
8867
+ retrievalMode,
8828
8868
  projectScopeMode: opts.projectScopeMode,
8829
8869
  projectHash: opts.projectHash,
8830
8870
  allowedProjectHashes: opts.allowedProjectHashes,
@@ -8843,6 +8883,7 @@ var Retriever = class {
8843
8883
  rerankWeights: opts.rerankWeights,
8844
8884
  decayPolicy: opts.decayPolicy,
8845
8885
  graphHop: opts.graphHop,
8886
+ retrievalMode,
8846
8887
  projectScopeMode: opts.projectScopeMode,
8847
8888
  projectHash: opts.projectHash,
8848
8889
  allowedProjectHashes: opts.allowedProjectHashes,
@@ -8862,6 +8903,7 @@ var Retriever = class {
8862
8903
  rerankWeights: opts.rerankWeights,
8863
8904
  decayPolicy: opts.decayPolicy,
8864
8905
  graphHop: opts.graphHop,
8906
+ retrievalMode,
8865
8907
  projectScopeMode: opts.projectScopeMode,
8866
8908
  projectHash: opts.projectHash,
8867
8909
  allowedProjectHashes: opts.allowedProjectHashes,
@@ -8882,14 +8924,37 @@ var Retriever = class {
8882
8924
  query,
8883
8925
  minScore: opts.minScore
8884
8926
  });
8927
+ const expandedSummary = retrievalMode === "session-event-hybrid" ? await this.expandSessionEventHybrid(filteredSummary, {
8928
+ query: qualityQuery,
8929
+ currentStateQuery: query,
8930
+ limit: opts.topK * 4
8931
+ }) : filteredSummary;
8932
+ const scopedExpandedSummary = retrievalMode === "session-event-hybrid" ? await this.applyScopeFilters(expandedSummary, {
8933
+ scope: opts.scope,
8934
+ projectScopeMode: opts.projectScopeMode,
8935
+ projectHash: opts.projectHash,
8936
+ allowedProjectHashes: opts.allowedProjectHashes,
8937
+ facets: opts.facets
8938
+ }) : expandedSummary;
8939
+ const finalSummary = retrievalMode === "session-event-hybrid" ? this.applyQualityFilters(scopedExpandedSummary, {
8940
+ query,
8941
+ minScore: opts.minScore
8942
+ }) : scopedExpandedSummary;
8885
8943
  current = {
8886
- results: filteredSummary,
8887
- candidateResults: filteredSummary,
8888
- matchResult: this.matcher.matchSearchResults(filteredSummary, () => 0)
8944
+ results: finalSummary,
8945
+ candidateResults: finalSummary,
8946
+ matchResult: this.matcher.matchSearchResults(finalSummary, () => 0)
8889
8947
  };
8890
8948
  fallbackTrace.push("fallback:summary");
8891
8949
  }
8892
- const memories = await this.enrichResults(current.results.slice(0, opts.topK), opts);
8950
+ const selectedResults = current.results.slice(0, opts.topK).filter((result) => {
8951
+ if (current.matchResult.confidence !== "none") return true;
8952
+ if (isLowConfidenceContextFallbackQuery(query)) {
8953
+ return (result.semanticScore ?? result.score) >= 0.5 || result.score >= 0.5;
8954
+ }
8955
+ return (result.semanticScore ?? result.score) >= 0.62 || result.score >= 0.62;
8956
+ });
8957
+ const memories = await this.enrichResults(selectedResults, opts, query);
8893
8958
  const context = this.buildContext(memories, opts.maxTokens);
8894
8959
  return {
8895
8960
  memories,
@@ -8897,7 +8962,7 @@ var Retriever = class {
8897
8962
  totalTokens: this.estimateTokens(context),
8898
8963
  context,
8899
8964
  fallbackTrace,
8900
- selectedDebug: current.results.slice(0, opts.topK).map((r) => this.debugDetailForResult(r)),
8965
+ selectedDebug: selectedResults.map((r) => this.debugDetailForResult(r)),
8901
8966
  candidateDebug: (current.candidateResults || []).slice(0, Math.max(opts.topK * 3, 20)).map((r) => this.debugDetailForResult(r)),
8902
8967
  rawQueryText: current.queryRewriteKind ? query : void 0,
8903
8968
  effectiveQueryText: current.effectiveQueryText,
@@ -8964,13 +9029,18 @@ var Retriever = class {
8964
9029
  initialResults = this.mergeResults(initialResults, rewrittenResults, input.topK * 3);
8965
9030
  }
8966
9031
  }
8967
- const expandedResults = input.graphHop?.enabled === false ? initialResults : await this.expandGraphHops(initialResults, {
9032
+ const graphExpandedResults = input.graphHop?.enabled === false ? initialResults : await this.expandGraphHops(initialResults, {
8968
9033
  query,
8969
9034
  queryGraphEnabled: this.queryGraphExpansionEnabled,
8970
9035
  maxHops: clampGraphHops(input.graphHop?.maxHops ?? 1),
8971
9036
  hopPenalty: Math.max(0, input.graphHop?.hopPenalty ?? 0.08),
8972
9037
  limit: input.topK * 4
8973
9038
  });
9039
+ const expandedResults = input.retrievalMode === "session-event-hybrid" ? await this.expandSessionEventHybrid(graphExpandedResults, {
9040
+ query: rerankQuery,
9041
+ currentStateQuery: query,
9042
+ limit: input.topK * 4
9043
+ }) : graphExpandedResults;
8974
9044
  const rerankedResults = input.rerankWithKeyword ? this.rerankByKeywordOverlap(expandedResults, rerankQuery, input.rerankWeights, input.decayPolicy) : expandedResults;
8975
9045
  const filtered = await this.applyScopeFilters(rerankedResults, {
8976
9046
  scope: input.scope,
@@ -8992,6 +9062,7 @@ var Retriever = class {
8992
9062
  if (isCurrentStateQuery(options.query)) {
8993
9063
  filtered = filtered.filter((result) => !isStaleOrSupersededContent(result.content));
8994
9064
  }
9065
+ filtered = filtered.filter((result) => !isLowSignalContextContent(result.content));
8995
9066
  filtered = filtered.filter(
8996
9067
  (result) => this.isGraphPathResult(result) || hasDiscriminativeTermOverlap(options.query, result.content)
8997
9068
  );
@@ -9017,6 +9088,47 @@ var Retriever = class {
9017
9088
  }
9018
9089
  return [...byId.values()].sort((a, b) => b.score - a.score).slice(0, limit);
9019
9090
  }
9091
+ async expandSessionEventHybrid(seeds, opts) {
9092
+ if (seeds.length === 0 || opts.limit <= seeds.length) return seeds;
9093
+ const queryTokens = this.tokenize(opts.query);
9094
+ if (queryTokens.length === 0) return seeds;
9095
+ const byId = /* @__PURE__ */ new Map();
9096
+ for (const seed of seeds) byId.set(seed.eventId, seed);
9097
+ const bestSeedBySession = /* @__PURE__ */ new Map();
9098
+ for (const seed of [...seeds].sort((a, b) => b.score - a.score || compareStable(a.eventId, b.eventId))) {
9099
+ if (!seed.sessionId || bestSeedBySession.has(seed.sessionId)) continue;
9100
+ bestSeedBySession.set(seed.sessionId, seed);
9101
+ }
9102
+ const suppressStaleState = isCurrentStateQuery(opts.currentStateQuery);
9103
+ for (const [sessionId, seed] of bestSeedBySession) {
9104
+ const sessionEvents = await this.eventStore.getSessionEvents(sessionId);
9105
+ for (const event of [...sessionEvents].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime())) {
9106
+ if (byId.has(event.id)) continue;
9107
+ if (isLowSignalContextContent(event.content)) continue;
9108
+ if (suppressStaleState && isStaleOrSupersededContent(event.content)) continue;
9109
+ const lexicalScore = this.keywordOverlap(queryTokens, this.tokenize(event.content));
9110
+ if (lexicalScore <= 0) continue;
9111
+ if (shouldApplyTechnicalGuard(opts.query) && !hasTechnicalTermOverlap(opts.query, event.content)) continue;
9112
+ const score = Math.min(0.95, Math.max(0.35, seed.score * 0.72 + lexicalScore * 0.28));
9113
+ const row = withRetrievalLane({
9114
+ id: `session-event-${seed.eventId}-${event.id}`,
9115
+ eventId: event.id,
9116
+ content: event.content,
9117
+ score,
9118
+ sessionId: event.sessionId,
9119
+ eventType: event.eventType,
9120
+ timestamp: event.timestamp.toISOString(),
9121
+ semanticScore: seed.semanticScore ?? seed.score,
9122
+ lexicalScore,
9123
+ recencyScore: seed.recencyScore
9124
+ }, { lane: "session_event", reason: `same_session:${seed.eventId}`, score });
9125
+ byId.set(row.eventId, row);
9126
+ if (byId.size >= opts.limit) break;
9127
+ }
9128
+ if (byId.size >= opts.limit) break;
9129
+ }
9130
+ return [...byId.values()].sort((a, b) => b.score - a.score || compareStable(a.eventId, b.eventId)).slice(0, opts.limit);
9131
+ }
9020
9132
  async expandGraphHops(seeds, opts) {
9021
9133
  const byId = /* @__PURE__ */ new Map();
9022
9134
  for (const s of seeds) byId.set(s.eventId, s);
@@ -9332,7 +9444,7 @@ var Retriever = class {
9332
9444
  async retrieveRecent(limit = 100) {
9333
9445
  return this.eventStore.getRecentEvents(limit);
9334
9446
  }
9335
- async enrichResults(results, options) {
9447
+ async enrichResults(results, options, query) {
9336
9448
  const memories = [];
9337
9449
  for (const result of results) {
9338
9450
  const event = await this.eventStore.getEvent(result.eventId);
@@ -9342,13 +9454,13 @@ var Retriever = class {
9342
9454
  }
9343
9455
  let sessionContext;
9344
9456
  if (options.includeSessionContext) {
9345
- sessionContext = await this.getSessionContext(event.sessionId, event.id);
9457
+ sessionContext = await this.getSessionContext(event.sessionId, event.id, query);
9346
9458
  }
9347
9459
  memories.push({ event, score: result.score, sessionContext });
9348
9460
  }
9349
9461
  return memories;
9350
9462
  }
9351
- async getSessionContext(sessionId, eventId) {
9463
+ async getSessionContext(sessionId, eventId, query) {
9352
9464
  const sessionEvents = await this.eventStore.getSessionEvents(sessionId);
9353
9465
  const eventIndex = sessionEvents.findIndex((e) => e.id === eventId);
9354
9466
  if (eventIndex === -1) return void 0;
@@ -9356,7 +9468,9 @@ var Retriever = class {
9356
9468
  const end = Math.min(sessionEvents.length, eventIndex + 2);
9357
9469
  const contextEvents = sessionEvents.slice(start, end);
9358
9470
  if (contextEvents.length <= 1) return void 0;
9359
- return contextEvents.filter((e) => e.id !== eventId).map((e) => `[${e.eventType}]: ${e.content.slice(0, 200)}...`).join("\n");
9471
+ const suppressStaleState = isCurrentStateQuery(query);
9472
+ const contextLines = contextEvents.filter((e) => e.id !== eventId).filter((e) => !isLowSignalContextContent(e.content)).filter((e) => !(suppressStaleState && isStaleOrSupersededContent(e.content))).map((e) => `[${e.eventType}]: ${e.content.slice(0, 200)}...`);
9473
+ return contextLines.length > 0 ? contextLines.join("\n") : void 0;
9360
9474
  }
9361
9475
  buildUnifiedContext(projectResult, sharedMemories) {
9362
9476
  let context = projectResult.context;