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.
@@ -2563,6 +2563,7 @@ var VectorOutbox = class {
2563
2563
  // src/core/retrieval-debug-lanes.ts
2564
2564
  var RETRIEVAL_DEBUG_LANE_NAMES = [
2565
2565
  "raw_event",
2566
+ "session_event",
2566
2567
  "session_summary",
2567
2568
  "graph_path",
2568
2569
  "facet_match"
@@ -8602,6 +8603,18 @@ var COMMAND_ARTIFACT_PATTERNS = [
8602
8603
  /<local-command-stdout>[\s\S]*?<\/local-command-stdout>/i,
8603
8604
  /<local-command-stderr>[\s\S]*?<\/local-command-stderr>/i
8604
8605
  ];
8606
+ var LOW_SIGNAL_CONTEXT_PATTERNS = [
8607
+ /<environment_context\b[\s\S]*<\/environment_context>/i,
8608
+ /<turn_aborted>/i,
8609
+ /^#\s*AGENTS\.md\s+instructions\b[\s\S]*<INSTRUCTIONS>/i,
8610
+ /^\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,
8611
+ /^\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,
8612
+ /^\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,
8613
+ /^\s*---\s*END\s+OF\s+CONTEXT\s+SUMMARY\b/i,
8614
+ /^\s*\[Your\s+active\s+task\s+list\s+was\s+preserved\s+across\s+context\s+compression\]/i,
8615
+ /^➜\s+\S+\s+git:\([^)]*\)\s+/i,
8616
+ /^\$\s+\S+/i
8617
+ ];
8605
8618
  var CONTINUATION_QUERY_PATTERNS = [
8606
8619
  /^\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,
8607
8620
  /^\s*(?:응\s*)?(?:이어서(?:\s*진행(?:해줘)?)?|계속(?:\s*해줘)?|다음\s*(?:단계|작업|추천\s*작업|추천|할\s*일)?(?:은|는)?(?:\s*(?:뭐야|진행(?:해줘)?))?\??|남은\s*(?:추가(?:로)?\s*)?(?:(?:할\s*만한\s*)?(?:작업|일)|할\s*일)?(?:은|는)?\s*(?:있어|있나|있나요|뭐야)\??|추천\s*작업(?:은|는)?(?:\s*뭐야)?\??|진행해줘)\s*$/i
@@ -8613,7 +8626,7 @@ var SHORT_REPAIR_FOLLOW_UP_PATTERNS = [
8613
8626
  var CURRENT_STATE_QUERY_PATTERNS = [
8614
8627
  /\bcurrent\b.*\b(?:state|status|deployment|blocker|pr|pull request)\b/i,
8615
8628
  /\b(?:still|as current|current)\b.*\b(?:unresolved|open|pending|not completed)\b/i,
8616
- /\b(?:old|obsolete|stale|resolved|already resolved)\b.*\b(?:current|still|unresolved|open|state|status)\b/i,
8629
+ /\b(?:old|obsolete|stale|resolved|already resolved)\b.*\b(?:current|still|unresolved|open|status)\b/i,
8617
8630
  /(?:현재|아직|이전|오래된|해결된).*(?:상태|미해결|열린|블로커|PR|풀리퀘스트)/i
8618
8631
  ];
8619
8632
  var STALE_CONTENT_PATTERNS = [
@@ -8759,6 +8772,21 @@ function isCommandArtifactQuery(query) {
8759
8772
  if (normalized.includes("command-name") || normalized.includes("command-message")) return true;
8760
8773
  return COMMAND_ARTIFACT_PATTERNS.some((pattern) => pattern.test(trimmed));
8761
8774
  }
8775
+ function isCommandArtifactContent(content) {
8776
+ const trimmed = content.trim();
8777
+ if (!trimmed) return false;
8778
+ const normalized = trimmed.toLowerCase();
8779
+ if (normalized.includes("local-command-stdout") || normalized.includes("local-command-stderr")) return true;
8780
+ if (normalized.includes("command-name") || normalized.includes("command-message")) return true;
8781
+ return COMMAND_ARTIFACT_PATTERNS.some((pattern) => pattern.test(trimmed));
8782
+ }
8783
+ function isLowSignalContextContent(content) {
8784
+ const trimmed = content.trim();
8785
+ if (!trimmed) return true;
8786
+ if (isCommandArtifactContent(trimmed)) return true;
8787
+ if (LOW_SIGNAL_CONTEXT_PATTERNS.some((pattern) => pattern.test(trimmed))) return true;
8788
+ return false;
8789
+ }
8762
8790
  function isGenericContinuationQuery(query) {
8763
8791
  const trimmed = query.trim();
8764
8792
  if (!trimmed) return false;
@@ -8776,6 +8804,16 @@ function isShortRepairFollowUpQuery(query) {
8776
8804
  if (tokens.length > 8) return false;
8777
8805
  return SHORT_REPAIR_FOLLOW_UP_PATTERNS.some((pattern) => pattern.test(trimmed));
8778
8806
  }
8807
+ function isLowConfidenceContextFallbackQuery(query) {
8808
+ const trimmed = query.trim();
8809
+ if (!trimmed) return false;
8810
+ if (isGenericContinuationQuery(trimmed) || isShortRepairFollowUpQuery(trimmed)) return true;
8811
+ const terms = new Set(tokenizeQualityText(trimmed));
8812
+ if ((terms.has("compacted") || terms.has("compaction")) && terms.has("handoff")) return false;
8813
+ const hasContinuationRecall = /^(?:continue|resume)\b/i.test(trimmed) && (terms.has("work") || terms.has("step") || terms.has("task") || terms.has("last") || terms.has("completed"));
8814
+ 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"));
8815
+ return hasContinuationRecall || hasValidationGateRecall;
8816
+ }
8779
8817
  function isCurrentStateQuery(query) {
8780
8818
  const trimmed = query.trim();
8781
8819
  if (!trimmed) return false;
@@ -8949,6 +8987,7 @@ var Retriever = class {
8949
8987
  }
8950
8988
  async retrieve(query, options = {}) {
8951
8989
  const opts = { ...DEFAULT_OPTIONS, ...options };
8990
+ const retrievalMode = options.retrievalMode ?? ((options.strategy ?? DEFAULT_OPTIONS.strategy) === "auto" ? "session-event-hybrid" : "event");
8952
8991
  const sessionFilter = opts.scope?.sessionId ?? opts.sessionId;
8953
8992
  const fallbackTrace = [];
8954
8993
  const qualityQuery = buildRetrievalQualityQuery(query);
@@ -8979,6 +9018,7 @@ var Retriever = class {
8979
9018
  decayPolicy: opts.decayPolicy,
8980
9019
  intentRewrite: opts.intentRewrite === true,
8981
9020
  graphHop: opts.graphHop,
9021
+ retrievalMode,
8982
9022
  projectScopeMode: opts.projectScopeMode,
8983
9023
  projectHash: opts.projectHash,
8984
9024
  allowedProjectHashes: opts.allowedProjectHashes,
@@ -8997,6 +9037,7 @@ var Retriever = class {
8997
9037
  rerankWeights: opts.rerankWeights,
8998
9038
  decayPolicy: opts.decayPolicy,
8999
9039
  graphHop: opts.graphHop,
9040
+ retrievalMode,
9000
9041
  projectScopeMode: opts.projectScopeMode,
9001
9042
  projectHash: opts.projectHash,
9002
9043
  allowedProjectHashes: opts.allowedProjectHashes,
@@ -9016,6 +9057,7 @@ var Retriever = class {
9016
9057
  rerankWeights: opts.rerankWeights,
9017
9058
  decayPolicy: opts.decayPolicy,
9018
9059
  graphHop: opts.graphHop,
9060
+ retrievalMode,
9019
9061
  projectScopeMode: opts.projectScopeMode,
9020
9062
  projectHash: opts.projectHash,
9021
9063
  allowedProjectHashes: opts.allowedProjectHashes,
@@ -9036,14 +9078,37 @@ var Retriever = class {
9036
9078
  query,
9037
9079
  minScore: opts.minScore
9038
9080
  });
9081
+ const expandedSummary = retrievalMode === "session-event-hybrid" ? await this.expandSessionEventHybrid(filteredSummary, {
9082
+ query: qualityQuery,
9083
+ currentStateQuery: query,
9084
+ limit: opts.topK * 4
9085
+ }) : filteredSummary;
9086
+ const scopedExpandedSummary = retrievalMode === "session-event-hybrid" ? await this.applyScopeFilters(expandedSummary, {
9087
+ scope: opts.scope,
9088
+ projectScopeMode: opts.projectScopeMode,
9089
+ projectHash: opts.projectHash,
9090
+ allowedProjectHashes: opts.allowedProjectHashes,
9091
+ facets: opts.facets
9092
+ }) : expandedSummary;
9093
+ const finalSummary = retrievalMode === "session-event-hybrid" ? this.applyQualityFilters(scopedExpandedSummary, {
9094
+ query,
9095
+ minScore: opts.minScore
9096
+ }) : scopedExpandedSummary;
9039
9097
  current = {
9040
- results: filteredSummary,
9041
- candidateResults: filteredSummary,
9042
- matchResult: this.matcher.matchSearchResults(filteredSummary, () => 0)
9098
+ results: finalSummary,
9099
+ candidateResults: finalSummary,
9100
+ matchResult: this.matcher.matchSearchResults(finalSummary, () => 0)
9043
9101
  };
9044
9102
  fallbackTrace.push("fallback:summary");
9045
9103
  }
9046
- const memories = await this.enrichResults(current.results.slice(0, opts.topK), opts);
9104
+ const selectedResults = current.results.slice(0, opts.topK).filter((result) => {
9105
+ if (current.matchResult.confidence !== "none") return true;
9106
+ if (isLowConfidenceContextFallbackQuery(query)) {
9107
+ return (result.semanticScore ?? result.score) >= 0.5 || result.score >= 0.5;
9108
+ }
9109
+ return (result.semanticScore ?? result.score) >= 0.62 || result.score >= 0.62;
9110
+ });
9111
+ const memories = await this.enrichResults(selectedResults, opts, query);
9047
9112
  const context = this.buildContext(memories, opts.maxTokens);
9048
9113
  return {
9049
9114
  memories,
@@ -9051,7 +9116,7 @@ var Retriever = class {
9051
9116
  totalTokens: this.estimateTokens(context),
9052
9117
  context,
9053
9118
  fallbackTrace,
9054
- selectedDebug: current.results.slice(0, opts.topK).map((r) => this.debugDetailForResult(r)),
9119
+ selectedDebug: selectedResults.map((r) => this.debugDetailForResult(r)),
9055
9120
  candidateDebug: (current.candidateResults || []).slice(0, Math.max(opts.topK * 3, 20)).map((r) => this.debugDetailForResult(r)),
9056
9121
  rawQueryText: current.queryRewriteKind ? query : void 0,
9057
9122
  effectiveQueryText: current.effectiveQueryText,
@@ -9118,13 +9183,18 @@ var Retriever = class {
9118
9183
  initialResults = this.mergeResults(initialResults, rewrittenResults, input.topK * 3);
9119
9184
  }
9120
9185
  }
9121
- const expandedResults = input.graphHop?.enabled === false ? initialResults : await this.expandGraphHops(initialResults, {
9186
+ const graphExpandedResults = input.graphHop?.enabled === false ? initialResults : await this.expandGraphHops(initialResults, {
9122
9187
  query,
9123
9188
  queryGraphEnabled: this.queryGraphExpansionEnabled,
9124
9189
  maxHops: clampGraphHops(input.graphHop?.maxHops ?? 1),
9125
9190
  hopPenalty: Math.max(0, input.graphHop?.hopPenalty ?? 0.08),
9126
9191
  limit: input.topK * 4
9127
9192
  });
9193
+ const expandedResults = input.retrievalMode === "session-event-hybrid" ? await this.expandSessionEventHybrid(graphExpandedResults, {
9194
+ query: rerankQuery,
9195
+ currentStateQuery: query,
9196
+ limit: input.topK * 4
9197
+ }) : graphExpandedResults;
9128
9198
  const rerankedResults = input.rerankWithKeyword ? this.rerankByKeywordOverlap(expandedResults, rerankQuery, input.rerankWeights, input.decayPolicy) : expandedResults;
9129
9199
  const filtered = await this.applyScopeFilters(rerankedResults, {
9130
9200
  scope: input.scope,
@@ -9146,6 +9216,7 @@ var Retriever = class {
9146
9216
  if (isCurrentStateQuery(options.query)) {
9147
9217
  filtered = filtered.filter((result) => !isStaleOrSupersededContent(result.content));
9148
9218
  }
9219
+ filtered = filtered.filter((result) => !isLowSignalContextContent(result.content));
9149
9220
  filtered = filtered.filter(
9150
9221
  (result) => this.isGraphPathResult(result) || hasDiscriminativeTermOverlap(options.query, result.content)
9151
9222
  );
@@ -9171,6 +9242,47 @@ var Retriever = class {
9171
9242
  }
9172
9243
  return [...byId.values()].sort((a, b) => b.score - a.score).slice(0, limit);
9173
9244
  }
9245
+ async expandSessionEventHybrid(seeds, opts) {
9246
+ if (seeds.length === 0 || opts.limit <= seeds.length) return seeds;
9247
+ const queryTokens = this.tokenize(opts.query);
9248
+ if (queryTokens.length === 0) return seeds;
9249
+ const byId = /* @__PURE__ */ new Map();
9250
+ for (const seed of seeds) byId.set(seed.eventId, seed);
9251
+ const bestSeedBySession = /* @__PURE__ */ new Map();
9252
+ for (const seed of [...seeds].sort((a, b) => b.score - a.score || compareStable(a.eventId, b.eventId))) {
9253
+ if (!seed.sessionId || bestSeedBySession.has(seed.sessionId)) continue;
9254
+ bestSeedBySession.set(seed.sessionId, seed);
9255
+ }
9256
+ const suppressStaleState = isCurrentStateQuery(opts.currentStateQuery);
9257
+ for (const [sessionId, seed] of bestSeedBySession) {
9258
+ const sessionEvents = await this.eventStore.getSessionEvents(sessionId);
9259
+ for (const event of [...sessionEvents].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime())) {
9260
+ if (byId.has(event.id)) continue;
9261
+ if (isLowSignalContextContent(event.content)) continue;
9262
+ if (suppressStaleState && isStaleOrSupersededContent(event.content)) continue;
9263
+ const lexicalScore = this.keywordOverlap(queryTokens, this.tokenize(event.content));
9264
+ if (lexicalScore <= 0) continue;
9265
+ if (shouldApplyTechnicalGuard(opts.query) && !hasTechnicalTermOverlap(opts.query, event.content)) continue;
9266
+ const score = Math.min(0.95, Math.max(0.35, seed.score * 0.72 + lexicalScore * 0.28));
9267
+ const row = withRetrievalLane({
9268
+ id: `session-event-${seed.eventId}-${event.id}`,
9269
+ eventId: event.id,
9270
+ content: event.content,
9271
+ score,
9272
+ sessionId: event.sessionId,
9273
+ eventType: event.eventType,
9274
+ timestamp: event.timestamp.toISOString(),
9275
+ semanticScore: seed.semanticScore ?? seed.score,
9276
+ lexicalScore,
9277
+ recencyScore: seed.recencyScore
9278
+ }, { lane: "session_event", reason: `same_session:${seed.eventId}`, score });
9279
+ byId.set(row.eventId, row);
9280
+ if (byId.size >= opts.limit) break;
9281
+ }
9282
+ if (byId.size >= opts.limit) break;
9283
+ }
9284
+ return [...byId.values()].sort((a, b) => b.score - a.score || compareStable(a.eventId, b.eventId)).slice(0, opts.limit);
9285
+ }
9174
9286
  async expandGraphHops(seeds, opts) {
9175
9287
  const byId = /* @__PURE__ */ new Map();
9176
9288
  for (const s of seeds) byId.set(s.eventId, s);
@@ -9486,7 +9598,7 @@ var Retriever = class {
9486
9598
  async retrieveRecent(limit = 100) {
9487
9599
  return this.eventStore.getRecentEvents(limit);
9488
9600
  }
9489
- async enrichResults(results, options) {
9601
+ async enrichResults(results, options, query) {
9490
9602
  const memories = [];
9491
9603
  for (const result of results) {
9492
9604
  const event = await this.eventStore.getEvent(result.eventId);
@@ -9496,13 +9608,13 @@ var Retriever = class {
9496
9608
  }
9497
9609
  let sessionContext;
9498
9610
  if (options.includeSessionContext) {
9499
- sessionContext = await this.getSessionContext(event.sessionId, event.id);
9611
+ sessionContext = await this.getSessionContext(event.sessionId, event.id, query);
9500
9612
  }
9501
9613
  memories.push({ event, score: result.score, sessionContext });
9502
9614
  }
9503
9615
  return memories;
9504
9616
  }
9505
- async getSessionContext(sessionId, eventId) {
9617
+ async getSessionContext(sessionId, eventId, query) {
9506
9618
  const sessionEvents = await this.eventStore.getSessionEvents(sessionId);
9507
9619
  const eventIndex = sessionEvents.findIndex((e) => e.id === eventId);
9508
9620
  if (eventIndex === -1) return void 0;
@@ -9510,7 +9622,9 @@ var Retriever = class {
9510
9622
  const end = Math.min(sessionEvents.length, eventIndex + 2);
9511
9623
  const contextEvents = sessionEvents.slice(start, end);
9512
9624
  if (contextEvents.length <= 1) return void 0;
9513
- return contextEvents.filter((e) => e.id !== eventId).map((e) => `[${e.eventType}]: ${e.content.slice(0, 200)}...`).join("\n");
9625
+ const suppressStaleState = isCurrentStateQuery(query);
9626
+ 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)}...`);
9627
+ return contextLines.length > 0 ? contextLines.join("\n") : void 0;
9514
9628
  }
9515
9629
  buildUnifiedContext(projectResult, sharedMemories) {
9516
9630
  let context = projectResult.context;