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"
@@ -8422,6 +8423,18 @@ var COMMAND_ARTIFACT_PATTERNS = [
8422
8423
  /<local-command-stdout>[\s\S]*?<\/local-command-stdout>/i,
8423
8424
  /<local-command-stderr>[\s\S]*?<\/local-command-stderr>/i
8424
8425
  ];
8426
+ var LOW_SIGNAL_CONTEXT_PATTERNS = [
8427
+ /<environment_context\b[\s\S]*<\/environment_context>/i,
8428
+ /<turn_aborted>/i,
8429
+ /^#\s*AGENTS\.md\s+instructions\b[\s\S]*<INSTRUCTIONS>/i,
8430
+ /^\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,
8431
+ /^\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,
8432
+ /^\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,
8433
+ /^\s*---\s*END\s+OF\s+CONTEXT\s+SUMMARY\b/i,
8434
+ /^\s*\[Your\s+active\s+task\s+list\s+was\s+preserved\s+across\s+context\s+compression\]/i,
8435
+ /^➜\s+\S+\s+git:\([^)]*\)\s+/i,
8436
+ /^\$\s+\S+/i
8437
+ ];
8425
8438
  var CONTINUATION_QUERY_PATTERNS = [
8426
8439
  /^\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,
8427
8440
  /^\s*(?:응\s*)?(?:이어서(?:\s*진행(?:해줘)?)?|계속(?:\s*해줘)?|다음\s*(?:단계|작업|추천\s*작업|추천|할\s*일)?(?:은|는)?(?:\s*(?:뭐야|진행(?:해줘)?))?\??|남은\s*(?:추가(?:로)?\s*)?(?:(?:할\s*만한\s*)?(?:작업|일)|할\s*일)?(?:은|는)?\s*(?:있어|있나|있나요|뭐야)\??|추천\s*작업(?:은|는)?(?:\s*뭐야)?\??|진행해줘)\s*$/i
@@ -8433,7 +8446,7 @@ var SHORT_REPAIR_FOLLOW_UP_PATTERNS = [
8433
8446
  var CURRENT_STATE_QUERY_PATTERNS = [
8434
8447
  /\bcurrent\b.*\b(?:state|status|deployment|blocker|pr|pull request)\b/i,
8435
8448
  /\b(?:still|as current|current)\b.*\b(?:unresolved|open|pending|not completed)\b/i,
8436
- /\b(?:old|obsolete|stale|resolved|already resolved)\b.*\b(?:current|still|unresolved|open|state|status)\b/i,
8449
+ /\b(?:old|obsolete|stale|resolved|already resolved)\b.*\b(?:current|still|unresolved|open|status)\b/i,
8437
8450
  /(?:현재|아직|이전|오래된|해결된).*(?:상태|미해결|열린|블로커|PR|풀리퀘스트)/i
8438
8451
  ];
8439
8452
  var STALE_CONTENT_PATTERNS = [
@@ -8579,6 +8592,21 @@ function isCommandArtifactQuery(query) {
8579
8592
  if (normalized.includes("command-name") || normalized.includes("command-message")) return true;
8580
8593
  return COMMAND_ARTIFACT_PATTERNS.some((pattern) => pattern.test(trimmed));
8581
8594
  }
8595
+ function isCommandArtifactContent(content) {
8596
+ const trimmed = content.trim();
8597
+ if (!trimmed) return false;
8598
+ const normalized = trimmed.toLowerCase();
8599
+ if (normalized.includes("local-command-stdout") || normalized.includes("local-command-stderr")) return true;
8600
+ if (normalized.includes("command-name") || normalized.includes("command-message")) return true;
8601
+ return COMMAND_ARTIFACT_PATTERNS.some((pattern) => pattern.test(trimmed));
8602
+ }
8603
+ function isLowSignalContextContent(content) {
8604
+ const trimmed = content.trim();
8605
+ if (!trimmed) return true;
8606
+ if (isCommandArtifactContent(trimmed)) return true;
8607
+ if (LOW_SIGNAL_CONTEXT_PATTERNS.some((pattern) => pattern.test(trimmed))) return true;
8608
+ return false;
8609
+ }
8582
8610
  function isGenericContinuationQuery(query) {
8583
8611
  const trimmed = query.trim();
8584
8612
  if (!trimmed) return false;
@@ -8596,6 +8624,16 @@ function isShortRepairFollowUpQuery(query) {
8596
8624
  if (tokens.length > 8) return false;
8597
8625
  return SHORT_REPAIR_FOLLOW_UP_PATTERNS.some((pattern) => pattern.test(trimmed));
8598
8626
  }
8627
+ function isLowConfidenceContextFallbackQuery(query) {
8628
+ const trimmed = query.trim();
8629
+ if (!trimmed) return false;
8630
+ if (isGenericContinuationQuery(trimmed) || isShortRepairFollowUpQuery(trimmed)) return true;
8631
+ const terms = new Set(tokenizeQualityText(trimmed));
8632
+ if ((terms.has("compacted") || terms.has("compaction")) && terms.has("handoff")) return false;
8633
+ const hasContinuationRecall = /^(?:continue|resume)\b/i.test(trimmed) && (terms.has("work") || terms.has("step") || terms.has("task") || terms.has("last") || terms.has("completed"));
8634
+ 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"));
8635
+ return hasContinuationRecall || hasValidationGateRecall;
8636
+ }
8599
8637
  function isCurrentStateQuery(query) {
8600
8638
  const trimmed = query.trim();
8601
8639
  if (!trimmed) return false;
@@ -8769,6 +8807,7 @@ var Retriever = class {
8769
8807
  }
8770
8808
  async retrieve(query, options = {}) {
8771
8809
  const opts = { ...DEFAULT_OPTIONS, ...options };
8810
+ const retrievalMode = options.retrievalMode ?? ((options.strategy ?? DEFAULT_OPTIONS.strategy) === "auto" ? "session-event-hybrid" : "event");
8772
8811
  const sessionFilter = opts.scope?.sessionId ?? opts.sessionId;
8773
8812
  const fallbackTrace = [];
8774
8813
  const qualityQuery = buildRetrievalQualityQuery(query);
@@ -8799,6 +8838,7 @@ var Retriever = class {
8799
8838
  decayPolicy: opts.decayPolicy,
8800
8839
  intentRewrite: opts.intentRewrite === true,
8801
8840
  graphHop: opts.graphHop,
8841
+ retrievalMode,
8802
8842
  projectScopeMode: opts.projectScopeMode,
8803
8843
  projectHash: opts.projectHash,
8804
8844
  allowedProjectHashes: opts.allowedProjectHashes,
@@ -8817,6 +8857,7 @@ var Retriever = class {
8817
8857
  rerankWeights: opts.rerankWeights,
8818
8858
  decayPolicy: opts.decayPolicy,
8819
8859
  graphHop: opts.graphHop,
8860
+ retrievalMode,
8820
8861
  projectScopeMode: opts.projectScopeMode,
8821
8862
  projectHash: opts.projectHash,
8822
8863
  allowedProjectHashes: opts.allowedProjectHashes,
@@ -8836,6 +8877,7 @@ var Retriever = class {
8836
8877
  rerankWeights: opts.rerankWeights,
8837
8878
  decayPolicy: opts.decayPolicy,
8838
8879
  graphHop: opts.graphHop,
8880
+ retrievalMode,
8839
8881
  projectScopeMode: opts.projectScopeMode,
8840
8882
  projectHash: opts.projectHash,
8841
8883
  allowedProjectHashes: opts.allowedProjectHashes,
@@ -8856,14 +8898,37 @@ var Retriever = class {
8856
8898
  query,
8857
8899
  minScore: opts.minScore
8858
8900
  });
8901
+ const expandedSummary = retrievalMode === "session-event-hybrid" ? await this.expandSessionEventHybrid(filteredSummary, {
8902
+ query: qualityQuery,
8903
+ currentStateQuery: query,
8904
+ limit: opts.topK * 4
8905
+ }) : filteredSummary;
8906
+ const scopedExpandedSummary = retrievalMode === "session-event-hybrid" ? await this.applyScopeFilters(expandedSummary, {
8907
+ scope: opts.scope,
8908
+ projectScopeMode: opts.projectScopeMode,
8909
+ projectHash: opts.projectHash,
8910
+ allowedProjectHashes: opts.allowedProjectHashes,
8911
+ facets: opts.facets
8912
+ }) : expandedSummary;
8913
+ const finalSummary = retrievalMode === "session-event-hybrid" ? this.applyQualityFilters(scopedExpandedSummary, {
8914
+ query,
8915
+ minScore: opts.minScore
8916
+ }) : scopedExpandedSummary;
8859
8917
  current = {
8860
- results: filteredSummary,
8861
- candidateResults: filteredSummary,
8862
- matchResult: this.matcher.matchSearchResults(filteredSummary, () => 0)
8918
+ results: finalSummary,
8919
+ candidateResults: finalSummary,
8920
+ matchResult: this.matcher.matchSearchResults(finalSummary, () => 0)
8863
8921
  };
8864
8922
  fallbackTrace.push("fallback:summary");
8865
8923
  }
8866
- const memories = await this.enrichResults(current.results.slice(0, opts.topK), opts);
8924
+ const selectedResults = current.results.slice(0, opts.topK).filter((result) => {
8925
+ if (current.matchResult.confidence !== "none") return true;
8926
+ if (isLowConfidenceContextFallbackQuery(query)) {
8927
+ return (result.semanticScore ?? result.score) >= 0.5 || result.score >= 0.5;
8928
+ }
8929
+ return (result.semanticScore ?? result.score) >= 0.62 || result.score >= 0.62;
8930
+ });
8931
+ const memories = await this.enrichResults(selectedResults, opts, query);
8867
8932
  const context = this.buildContext(memories, opts.maxTokens);
8868
8933
  return {
8869
8934
  memories,
@@ -8871,7 +8936,7 @@ var Retriever = class {
8871
8936
  totalTokens: this.estimateTokens(context),
8872
8937
  context,
8873
8938
  fallbackTrace,
8874
- selectedDebug: current.results.slice(0, opts.topK).map((r) => this.debugDetailForResult(r)),
8939
+ selectedDebug: selectedResults.map((r) => this.debugDetailForResult(r)),
8875
8940
  candidateDebug: (current.candidateResults || []).slice(0, Math.max(opts.topK * 3, 20)).map((r) => this.debugDetailForResult(r)),
8876
8941
  rawQueryText: current.queryRewriteKind ? query : void 0,
8877
8942
  effectiveQueryText: current.effectiveQueryText,
@@ -8938,13 +9003,18 @@ var Retriever = class {
8938
9003
  initialResults = this.mergeResults(initialResults, rewrittenResults, input.topK * 3);
8939
9004
  }
8940
9005
  }
8941
- const expandedResults = input.graphHop?.enabled === false ? initialResults : await this.expandGraphHops(initialResults, {
9006
+ const graphExpandedResults = input.graphHop?.enabled === false ? initialResults : await this.expandGraphHops(initialResults, {
8942
9007
  query,
8943
9008
  queryGraphEnabled: this.queryGraphExpansionEnabled,
8944
9009
  maxHops: clampGraphHops(input.graphHop?.maxHops ?? 1),
8945
9010
  hopPenalty: Math.max(0, input.graphHop?.hopPenalty ?? 0.08),
8946
9011
  limit: input.topK * 4
8947
9012
  });
9013
+ const expandedResults = input.retrievalMode === "session-event-hybrid" ? await this.expandSessionEventHybrid(graphExpandedResults, {
9014
+ query: rerankQuery,
9015
+ currentStateQuery: query,
9016
+ limit: input.topK * 4
9017
+ }) : graphExpandedResults;
8948
9018
  const rerankedResults = input.rerankWithKeyword ? this.rerankByKeywordOverlap(expandedResults, rerankQuery, input.rerankWeights, input.decayPolicy) : expandedResults;
8949
9019
  const filtered = await this.applyScopeFilters(rerankedResults, {
8950
9020
  scope: input.scope,
@@ -8966,6 +9036,7 @@ var Retriever = class {
8966
9036
  if (isCurrentStateQuery(options.query)) {
8967
9037
  filtered = filtered.filter((result) => !isStaleOrSupersededContent(result.content));
8968
9038
  }
9039
+ filtered = filtered.filter((result) => !isLowSignalContextContent(result.content));
8969
9040
  filtered = filtered.filter(
8970
9041
  (result) => this.isGraphPathResult(result) || hasDiscriminativeTermOverlap(options.query, result.content)
8971
9042
  );
@@ -8991,6 +9062,47 @@ var Retriever = class {
8991
9062
  }
8992
9063
  return [...byId.values()].sort((a, b) => b.score - a.score).slice(0, limit);
8993
9064
  }
9065
+ async expandSessionEventHybrid(seeds, opts) {
9066
+ if (seeds.length === 0 || opts.limit <= seeds.length) return seeds;
9067
+ const queryTokens = this.tokenize(opts.query);
9068
+ if (queryTokens.length === 0) return seeds;
9069
+ const byId = /* @__PURE__ */ new Map();
9070
+ for (const seed of seeds) byId.set(seed.eventId, seed);
9071
+ const bestSeedBySession = /* @__PURE__ */ new Map();
9072
+ for (const seed of [...seeds].sort((a, b) => b.score - a.score || compareStable(a.eventId, b.eventId))) {
9073
+ if (!seed.sessionId || bestSeedBySession.has(seed.sessionId)) continue;
9074
+ bestSeedBySession.set(seed.sessionId, seed);
9075
+ }
9076
+ const suppressStaleState = isCurrentStateQuery(opts.currentStateQuery);
9077
+ for (const [sessionId, seed] of bestSeedBySession) {
9078
+ const sessionEvents = await this.eventStore.getSessionEvents(sessionId);
9079
+ for (const event of [...sessionEvents].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime())) {
9080
+ if (byId.has(event.id)) continue;
9081
+ if (isLowSignalContextContent(event.content)) continue;
9082
+ if (suppressStaleState && isStaleOrSupersededContent(event.content)) continue;
9083
+ const lexicalScore = this.keywordOverlap(queryTokens, this.tokenize(event.content));
9084
+ if (lexicalScore <= 0) continue;
9085
+ if (shouldApplyTechnicalGuard(opts.query) && !hasTechnicalTermOverlap(opts.query, event.content)) continue;
9086
+ const score = Math.min(0.95, Math.max(0.35, seed.score * 0.72 + lexicalScore * 0.28));
9087
+ const row = withRetrievalLane({
9088
+ id: `session-event-${seed.eventId}-${event.id}`,
9089
+ eventId: event.id,
9090
+ content: event.content,
9091
+ score,
9092
+ sessionId: event.sessionId,
9093
+ eventType: event.eventType,
9094
+ timestamp: event.timestamp.toISOString(),
9095
+ semanticScore: seed.semanticScore ?? seed.score,
9096
+ lexicalScore,
9097
+ recencyScore: seed.recencyScore
9098
+ }, { lane: "session_event", reason: `same_session:${seed.eventId}`, score });
9099
+ byId.set(row.eventId, row);
9100
+ if (byId.size >= opts.limit) break;
9101
+ }
9102
+ if (byId.size >= opts.limit) break;
9103
+ }
9104
+ return [...byId.values()].sort((a, b) => b.score - a.score || compareStable(a.eventId, b.eventId)).slice(0, opts.limit);
9105
+ }
8994
9106
  async expandGraphHops(seeds, opts) {
8995
9107
  const byId = /* @__PURE__ */ new Map();
8996
9108
  for (const s of seeds) byId.set(s.eventId, s);
@@ -9306,7 +9418,7 @@ var Retriever = class {
9306
9418
  async retrieveRecent(limit = 100) {
9307
9419
  return this.eventStore.getRecentEvents(limit);
9308
9420
  }
9309
- async enrichResults(results, options) {
9421
+ async enrichResults(results, options, query) {
9310
9422
  const memories = [];
9311
9423
  for (const result of results) {
9312
9424
  const event = await this.eventStore.getEvent(result.eventId);
@@ -9316,13 +9428,13 @@ var Retriever = class {
9316
9428
  }
9317
9429
  let sessionContext;
9318
9430
  if (options.includeSessionContext) {
9319
- sessionContext = await this.getSessionContext(event.sessionId, event.id);
9431
+ sessionContext = await this.getSessionContext(event.sessionId, event.id, query);
9320
9432
  }
9321
9433
  memories.push({ event, score: result.score, sessionContext });
9322
9434
  }
9323
9435
  return memories;
9324
9436
  }
9325
- async getSessionContext(sessionId, eventId) {
9437
+ async getSessionContext(sessionId, eventId, query) {
9326
9438
  const sessionEvents = await this.eventStore.getSessionEvents(sessionId);
9327
9439
  const eventIndex = sessionEvents.findIndex((e) => e.id === eventId);
9328
9440
  if (eventIndex === -1) return void 0;
@@ -9330,7 +9442,9 @@ var Retriever = class {
9330
9442
  const end = Math.min(sessionEvents.length, eventIndex + 2);
9331
9443
  const contextEvents = sessionEvents.slice(start, end);
9332
9444
  if (contextEvents.length <= 1) return void 0;
9333
- return contextEvents.filter((e) => e.id !== eventId).map((e) => `[${e.eventType}]: ${e.content.slice(0, 200)}...`).join("\n");
9445
+ const suppressStaleState = isCurrentStateQuery(query);
9446
+ 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)}...`);
9447
+ return contextLines.length > 0 ? contextLines.join("\n") : void 0;
9334
9448
  }
9335
9449
  buildUnifiedContext(projectResult, sharedMemories) {
9336
9450
  let context = projectResult.context;