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.
@@ -2569,6 +2569,7 @@ var VectorOutbox = class {
2569
2569
  // src/core/retrieval-debug-lanes.ts
2570
2570
  var RETRIEVAL_DEBUG_LANE_NAMES = [
2571
2571
  "raw_event",
2572
+ "session_event",
2572
2573
  "session_summary",
2573
2574
  "graph_path",
2574
2575
  "facet_match"
@@ -8428,6 +8429,18 @@ var COMMAND_ARTIFACT_PATTERNS = [
8428
8429
  /<local-command-stdout>[\s\S]*?<\/local-command-stdout>/i,
8429
8430
  /<local-command-stderr>[\s\S]*?<\/local-command-stderr>/i
8430
8431
  ];
8432
+ var LOW_SIGNAL_CONTEXT_PATTERNS = [
8433
+ /<environment_context\b[\s\S]*<\/environment_context>/i,
8434
+ /<turn_aborted>/i,
8435
+ /^#\s*AGENTS\.md\s+instructions\b[\s\S]*<INSTRUCTIONS>/i,
8436
+ /^\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,
8437
+ /^\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,
8438
+ /^\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,
8439
+ /^\s*---\s*END\s+OF\s+CONTEXT\s+SUMMARY\b/i,
8440
+ /^\s*\[Your\s+active\s+task\s+list\s+was\s+preserved\s+across\s+context\s+compression\]/i,
8441
+ /^➜\s+\S+\s+git:\([^)]*\)\s+/i,
8442
+ /^\$\s+\S+/i
8443
+ ];
8431
8444
  var CONTINUATION_QUERY_PATTERNS = [
8432
8445
  /^\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,
8433
8446
  /^\s*(?:응\s*)?(?:이어서(?:\s*진행(?:해줘)?)?|계속(?:\s*해줘)?|다음\s*(?:단계|작업|추천\s*작업|추천|할\s*일)?(?:은|는)?(?:\s*(?:뭐야|진행(?:해줘)?))?\??|남은\s*(?:추가(?:로)?\s*)?(?:(?:할\s*만한\s*)?(?:작업|일)|할\s*일)?(?:은|는)?\s*(?:있어|있나|있나요|뭐야)\??|추천\s*작업(?:은|는)?(?:\s*뭐야)?\??|진행해줘)\s*$/i
@@ -8439,7 +8452,7 @@ var SHORT_REPAIR_FOLLOW_UP_PATTERNS = [
8439
8452
  var CURRENT_STATE_QUERY_PATTERNS = [
8440
8453
  /\bcurrent\b.*\b(?:state|status|deployment|blocker|pr|pull request)\b/i,
8441
8454
  /\b(?:still|as current|current)\b.*\b(?:unresolved|open|pending|not completed)\b/i,
8442
- /\b(?:old|obsolete|stale|resolved|already resolved)\b.*\b(?:current|still|unresolved|open|state|status)\b/i,
8455
+ /\b(?:old|obsolete|stale|resolved|already resolved)\b.*\b(?:current|still|unresolved|open|status)\b/i,
8443
8456
  /(?:현재|아직|이전|오래된|해결된).*(?:상태|미해결|열린|블로커|PR|풀리퀘스트)/i
8444
8457
  ];
8445
8458
  var STALE_CONTENT_PATTERNS = [
@@ -8585,6 +8598,21 @@ function isCommandArtifactQuery(query) {
8585
8598
  if (normalized.includes("command-name") || normalized.includes("command-message")) return true;
8586
8599
  return COMMAND_ARTIFACT_PATTERNS.some((pattern) => pattern.test(trimmed));
8587
8600
  }
8601
+ function isCommandArtifactContent(content) {
8602
+ const trimmed = content.trim();
8603
+ if (!trimmed) return false;
8604
+ const normalized = trimmed.toLowerCase();
8605
+ if (normalized.includes("local-command-stdout") || normalized.includes("local-command-stderr")) return true;
8606
+ if (normalized.includes("command-name") || normalized.includes("command-message")) return true;
8607
+ return COMMAND_ARTIFACT_PATTERNS.some((pattern) => pattern.test(trimmed));
8608
+ }
8609
+ function isLowSignalContextContent(content) {
8610
+ const trimmed = content.trim();
8611
+ if (!trimmed) return true;
8612
+ if (isCommandArtifactContent(trimmed)) return true;
8613
+ if (LOW_SIGNAL_CONTEXT_PATTERNS.some((pattern) => pattern.test(trimmed))) return true;
8614
+ return false;
8615
+ }
8588
8616
  function isGenericContinuationQuery(query) {
8589
8617
  const trimmed = query.trim();
8590
8618
  if (!trimmed) return false;
@@ -8602,6 +8630,16 @@ function isShortRepairFollowUpQuery(query) {
8602
8630
  if (tokens.length > 8) return false;
8603
8631
  return SHORT_REPAIR_FOLLOW_UP_PATTERNS.some((pattern) => pattern.test(trimmed));
8604
8632
  }
8633
+ function isLowConfidenceContextFallbackQuery(query) {
8634
+ const trimmed = query.trim();
8635
+ if (!trimmed) return false;
8636
+ if (isGenericContinuationQuery(trimmed) || isShortRepairFollowUpQuery(trimmed)) return true;
8637
+ const terms = new Set(tokenizeQualityText(trimmed));
8638
+ if ((terms.has("compacted") || terms.has("compaction")) && terms.has("handoff")) return false;
8639
+ const hasContinuationRecall = /^(?:continue|resume)\b/i.test(trimmed) && (terms.has("work") || terms.has("step") || terms.has("task") || terms.has("last") || terms.has("completed"));
8640
+ 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"));
8641
+ return hasContinuationRecall || hasValidationGateRecall;
8642
+ }
8605
8643
  function isCurrentStateQuery(query) {
8606
8644
  const trimmed = query.trim();
8607
8645
  if (!trimmed) return false;
@@ -8775,6 +8813,7 @@ var Retriever = class {
8775
8813
  }
8776
8814
  async retrieve(query, options = {}) {
8777
8815
  const opts = { ...DEFAULT_OPTIONS, ...options };
8816
+ const retrievalMode = options.retrievalMode ?? ((options.strategy ?? DEFAULT_OPTIONS.strategy) === "auto" ? "session-event-hybrid" : "event");
8778
8817
  const sessionFilter = opts.scope?.sessionId ?? opts.sessionId;
8779
8818
  const fallbackTrace = [];
8780
8819
  const qualityQuery = buildRetrievalQualityQuery(query);
@@ -8805,6 +8844,7 @@ var Retriever = class {
8805
8844
  decayPolicy: opts.decayPolicy,
8806
8845
  intentRewrite: opts.intentRewrite === true,
8807
8846
  graphHop: opts.graphHop,
8847
+ retrievalMode,
8808
8848
  projectScopeMode: opts.projectScopeMode,
8809
8849
  projectHash: opts.projectHash,
8810
8850
  allowedProjectHashes: opts.allowedProjectHashes,
@@ -8823,6 +8863,7 @@ var Retriever = class {
8823
8863
  rerankWeights: opts.rerankWeights,
8824
8864
  decayPolicy: opts.decayPolicy,
8825
8865
  graphHop: opts.graphHop,
8866
+ retrievalMode,
8826
8867
  projectScopeMode: opts.projectScopeMode,
8827
8868
  projectHash: opts.projectHash,
8828
8869
  allowedProjectHashes: opts.allowedProjectHashes,
@@ -8842,6 +8883,7 @@ var Retriever = class {
8842
8883
  rerankWeights: opts.rerankWeights,
8843
8884
  decayPolicy: opts.decayPolicy,
8844
8885
  graphHop: opts.graphHop,
8886
+ retrievalMode,
8845
8887
  projectScopeMode: opts.projectScopeMode,
8846
8888
  projectHash: opts.projectHash,
8847
8889
  allowedProjectHashes: opts.allowedProjectHashes,
@@ -8862,14 +8904,37 @@ var Retriever = class {
8862
8904
  query,
8863
8905
  minScore: opts.minScore
8864
8906
  });
8907
+ const expandedSummary = retrievalMode === "session-event-hybrid" ? await this.expandSessionEventHybrid(filteredSummary, {
8908
+ query: qualityQuery,
8909
+ currentStateQuery: query,
8910
+ limit: opts.topK * 4
8911
+ }) : filteredSummary;
8912
+ const scopedExpandedSummary = retrievalMode === "session-event-hybrid" ? await this.applyScopeFilters(expandedSummary, {
8913
+ scope: opts.scope,
8914
+ projectScopeMode: opts.projectScopeMode,
8915
+ projectHash: opts.projectHash,
8916
+ allowedProjectHashes: opts.allowedProjectHashes,
8917
+ facets: opts.facets
8918
+ }) : expandedSummary;
8919
+ const finalSummary = retrievalMode === "session-event-hybrid" ? this.applyQualityFilters(scopedExpandedSummary, {
8920
+ query,
8921
+ minScore: opts.minScore
8922
+ }) : scopedExpandedSummary;
8865
8923
  current = {
8866
- results: filteredSummary,
8867
- candidateResults: filteredSummary,
8868
- matchResult: this.matcher.matchSearchResults(filteredSummary, () => 0)
8924
+ results: finalSummary,
8925
+ candidateResults: finalSummary,
8926
+ matchResult: this.matcher.matchSearchResults(finalSummary, () => 0)
8869
8927
  };
8870
8928
  fallbackTrace.push("fallback:summary");
8871
8929
  }
8872
- const memories = await this.enrichResults(current.results.slice(0, opts.topK), opts);
8930
+ const selectedResults = current.results.slice(0, opts.topK).filter((result) => {
8931
+ if (current.matchResult.confidence !== "none") return true;
8932
+ if (isLowConfidenceContextFallbackQuery(query)) {
8933
+ return (result.semanticScore ?? result.score) >= 0.5 || result.score >= 0.5;
8934
+ }
8935
+ return (result.semanticScore ?? result.score) >= 0.62 || result.score >= 0.62;
8936
+ });
8937
+ const memories = await this.enrichResults(selectedResults, opts, query);
8873
8938
  const context = this.buildContext(memories, opts.maxTokens);
8874
8939
  return {
8875
8940
  memories,
@@ -8877,7 +8942,7 @@ var Retriever = class {
8877
8942
  totalTokens: this.estimateTokens(context),
8878
8943
  context,
8879
8944
  fallbackTrace,
8880
- selectedDebug: current.results.slice(0, opts.topK).map((r) => this.debugDetailForResult(r)),
8945
+ selectedDebug: selectedResults.map((r) => this.debugDetailForResult(r)),
8881
8946
  candidateDebug: (current.candidateResults || []).slice(0, Math.max(opts.topK * 3, 20)).map((r) => this.debugDetailForResult(r)),
8882
8947
  rawQueryText: current.queryRewriteKind ? query : void 0,
8883
8948
  effectiveQueryText: current.effectiveQueryText,
@@ -8944,13 +9009,18 @@ var Retriever = class {
8944
9009
  initialResults = this.mergeResults(initialResults, rewrittenResults, input.topK * 3);
8945
9010
  }
8946
9011
  }
8947
- const expandedResults = input.graphHop?.enabled === false ? initialResults : await this.expandGraphHops(initialResults, {
9012
+ const graphExpandedResults = input.graphHop?.enabled === false ? initialResults : await this.expandGraphHops(initialResults, {
8948
9013
  query,
8949
9014
  queryGraphEnabled: this.queryGraphExpansionEnabled,
8950
9015
  maxHops: clampGraphHops(input.graphHop?.maxHops ?? 1),
8951
9016
  hopPenalty: Math.max(0, input.graphHop?.hopPenalty ?? 0.08),
8952
9017
  limit: input.topK * 4
8953
9018
  });
9019
+ const expandedResults = input.retrievalMode === "session-event-hybrid" ? await this.expandSessionEventHybrid(graphExpandedResults, {
9020
+ query: rerankQuery,
9021
+ currentStateQuery: query,
9022
+ limit: input.topK * 4
9023
+ }) : graphExpandedResults;
8954
9024
  const rerankedResults = input.rerankWithKeyword ? this.rerankByKeywordOverlap(expandedResults, rerankQuery, input.rerankWeights, input.decayPolicy) : expandedResults;
8955
9025
  const filtered = await this.applyScopeFilters(rerankedResults, {
8956
9026
  scope: input.scope,
@@ -8972,6 +9042,7 @@ var Retriever = class {
8972
9042
  if (isCurrentStateQuery(options.query)) {
8973
9043
  filtered = filtered.filter((result) => !isStaleOrSupersededContent(result.content));
8974
9044
  }
9045
+ filtered = filtered.filter((result) => !isLowSignalContextContent(result.content));
8975
9046
  filtered = filtered.filter(
8976
9047
  (result) => this.isGraphPathResult(result) || hasDiscriminativeTermOverlap(options.query, result.content)
8977
9048
  );
@@ -8997,6 +9068,47 @@ var Retriever = class {
8997
9068
  }
8998
9069
  return [...byId.values()].sort((a, b) => b.score - a.score).slice(0, limit);
8999
9070
  }
9071
+ async expandSessionEventHybrid(seeds, opts) {
9072
+ if (seeds.length === 0 || opts.limit <= seeds.length) return seeds;
9073
+ const queryTokens = this.tokenize(opts.query);
9074
+ if (queryTokens.length === 0) return seeds;
9075
+ const byId = /* @__PURE__ */ new Map();
9076
+ for (const seed of seeds) byId.set(seed.eventId, seed);
9077
+ const bestSeedBySession = /* @__PURE__ */ new Map();
9078
+ for (const seed of [...seeds].sort((a, b) => b.score - a.score || compareStable(a.eventId, b.eventId))) {
9079
+ if (!seed.sessionId || bestSeedBySession.has(seed.sessionId)) continue;
9080
+ bestSeedBySession.set(seed.sessionId, seed);
9081
+ }
9082
+ const suppressStaleState = isCurrentStateQuery(opts.currentStateQuery);
9083
+ for (const [sessionId, seed] of bestSeedBySession) {
9084
+ const sessionEvents = await this.eventStore.getSessionEvents(sessionId);
9085
+ for (const event of [...sessionEvents].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime())) {
9086
+ if (byId.has(event.id)) continue;
9087
+ if (isLowSignalContextContent(event.content)) continue;
9088
+ if (suppressStaleState && isStaleOrSupersededContent(event.content)) continue;
9089
+ const lexicalScore = this.keywordOverlap(queryTokens, this.tokenize(event.content));
9090
+ if (lexicalScore <= 0) continue;
9091
+ if (shouldApplyTechnicalGuard(opts.query) && !hasTechnicalTermOverlap(opts.query, event.content)) continue;
9092
+ const score = Math.min(0.95, Math.max(0.35, seed.score * 0.72 + lexicalScore * 0.28));
9093
+ const row = withRetrievalLane({
9094
+ id: `session-event-${seed.eventId}-${event.id}`,
9095
+ eventId: event.id,
9096
+ content: event.content,
9097
+ score,
9098
+ sessionId: event.sessionId,
9099
+ eventType: event.eventType,
9100
+ timestamp: event.timestamp.toISOString(),
9101
+ semanticScore: seed.semanticScore ?? seed.score,
9102
+ lexicalScore,
9103
+ recencyScore: seed.recencyScore
9104
+ }, { lane: "session_event", reason: `same_session:${seed.eventId}`, score });
9105
+ byId.set(row.eventId, row);
9106
+ if (byId.size >= opts.limit) break;
9107
+ }
9108
+ if (byId.size >= opts.limit) break;
9109
+ }
9110
+ return [...byId.values()].sort((a, b) => b.score - a.score || compareStable(a.eventId, b.eventId)).slice(0, opts.limit);
9111
+ }
9000
9112
  async expandGraphHops(seeds, opts) {
9001
9113
  const byId = /* @__PURE__ */ new Map();
9002
9114
  for (const s of seeds) byId.set(s.eventId, s);
@@ -9312,7 +9424,7 @@ var Retriever = class {
9312
9424
  async retrieveRecent(limit = 100) {
9313
9425
  return this.eventStore.getRecentEvents(limit);
9314
9426
  }
9315
- async enrichResults(results, options) {
9427
+ async enrichResults(results, options, query) {
9316
9428
  const memories = [];
9317
9429
  for (const result of results) {
9318
9430
  const event = await this.eventStore.getEvent(result.eventId);
@@ -9322,13 +9434,13 @@ var Retriever = class {
9322
9434
  }
9323
9435
  let sessionContext;
9324
9436
  if (options.includeSessionContext) {
9325
- sessionContext = await this.getSessionContext(event.sessionId, event.id);
9437
+ sessionContext = await this.getSessionContext(event.sessionId, event.id, query);
9326
9438
  }
9327
9439
  memories.push({ event, score: result.score, sessionContext });
9328
9440
  }
9329
9441
  return memories;
9330
9442
  }
9331
- async getSessionContext(sessionId, eventId) {
9443
+ async getSessionContext(sessionId, eventId, query) {
9332
9444
  const sessionEvents = await this.eventStore.getSessionEvents(sessionId);
9333
9445
  const eventIndex = sessionEvents.findIndex((e) => e.id === eventId);
9334
9446
  if (eventIndex === -1) return void 0;
@@ -9336,7 +9448,9 @@ var Retriever = class {
9336
9448
  const end = Math.min(sessionEvents.length, eventIndex + 2);
9337
9449
  const contextEvents = sessionEvents.slice(start, end);
9338
9450
  if (contextEvents.length <= 1) return void 0;
9339
- return contextEvents.filter((e) => e.id !== eventId).map((e) => `[${e.eventType}]: ${e.content.slice(0, 200)}...`).join("\n");
9451
+ const suppressStaleState = isCurrentStateQuery(query);
9452
+ 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)}...`);
9453
+ return contextLines.length > 0 ? contextLines.join("\n") : void 0;
9340
9454
  }
9341
9455
  buildUnifiedContext(projectResult, sharedMemories) {
9342
9456
  let context = projectResult.context;