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.
@@ -2681,6 +2681,7 @@ var VectorOutbox = class {
2681
2681
  // src/core/retrieval-debug-lanes.ts
2682
2682
  var RETRIEVAL_DEBUG_LANE_NAMES = [
2683
2683
  "raw_event",
2684
+ "session_event",
2684
2685
  "session_summary",
2685
2686
  "graph_path",
2686
2687
  "facet_match"
@@ -8780,6 +8781,18 @@ var COMMAND_ARTIFACT_PATTERNS = [
8780
8781
  /<local-command-stdout>[\s\S]*?<\/local-command-stdout>/i,
8781
8782
  /<local-command-stderr>[\s\S]*?<\/local-command-stderr>/i
8782
8783
  ];
8784
+ var LOW_SIGNAL_CONTEXT_PATTERNS = [
8785
+ /<environment_context\b[\s\S]*<\/environment_context>/i,
8786
+ /<turn_aborted>/i,
8787
+ /^#\s*AGENTS\.md\s+instructions\b[\s\S]*<INSTRUCTIONS>/i,
8788
+ /^\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,
8789
+ /^\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,
8790
+ /^\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,
8791
+ /^\s*---\s*END\s+OF\s+CONTEXT\s+SUMMARY\b/i,
8792
+ /^\s*\[Your\s+active\s+task\s+list\s+was\s+preserved\s+across\s+context\s+compression\]/i,
8793
+ /^➜\s+\S+\s+git:\([^)]*\)\s+/i,
8794
+ /^\$\s+\S+/i
8795
+ ];
8783
8796
  var CONTINUATION_QUERY_PATTERNS = [
8784
8797
  /^\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,
8785
8798
  /^\s*(?:응\s*)?(?:이어서(?:\s*진행(?:해줘)?)?|계속(?:\s*해줘)?|다음\s*(?:단계|작업|추천\s*작업|추천|할\s*일)?(?:은|는)?(?:\s*(?:뭐야|진행(?:해줘)?))?\??|남은\s*(?:추가(?:로)?\s*)?(?:(?:할\s*만한\s*)?(?:작업|일)|할\s*일)?(?:은|는)?\s*(?:있어|있나|있나요|뭐야)\??|추천\s*작업(?:은|는)?(?:\s*뭐야)?\??|진행해줘)\s*$/i
@@ -8791,7 +8804,7 @@ var SHORT_REPAIR_FOLLOW_UP_PATTERNS = [
8791
8804
  var CURRENT_STATE_QUERY_PATTERNS = [
8792
8805
  /\bcurrent\b.*\b(?:state|status|deployment|blocker|pr|pull request)\b/i,
8793
8806
  /\b(?:still|as current|current)\b.*\b(?:unresolved|open|pending|not completed)\b/i,
8794
- /\b(?:old|obsolete|stale|resolved|already resolved)\b.*\b(?:current|still|unresolved|open|state|status)\b/i,
8807
+ /\b(?:old|obsolete|stale|resolved|already resolved)\b.*\b(?:current|still|unresolved|open|status)\b/i,
8795
8808
  /(?:현재|아직|이전|오래된|해결된).*(?:상태|미해결|열린|블로커|PR|풀리퀘스트)/i
8796
8809
  ];
8797
8810
  var STALE_CONTENT_PATTERNS = [
@@ -8937,6 +8950,21 @@ function isCommandArtifactQuery(query) {
8937
8950
  if (normalized.includes("command-name") || normalized.includes("command-message")) return true;
8938
8951
  return COMMAND_ARTIFACT_PATTERNS.some((pattern) => pattern.test(trimmed));
8939
8952
  }
8953
+ function isCommandArtifactContent(content) {
8954
+ const trimmed = content.trim();
8955
+ if (!trimmed) return false;
8956
+ const normalized = trimmed.toLowerCase();
8957
+ if (normalized.includes("local-command-stdout") || normalized.includes("local-command-stderr")) return true;
8958
+ if (normalized.includes("command-name") || normalized.includes("command-message")) return true;
8959
+ return COMMAND_ARTIFACT_PATTERNS.some((pattern) => pattern.test(trimmed));
8960
+ }
8961
+ function isLowSignalContextContent(content) {
8962
+ const trimmed = content.trim();
8963
+ if (!trimmed) return true;
8964
+ if (isCommandArtifactContent(trimmed)) return true;
8965
+ if (LOW_SIGNAL_CONTEXT_PATTERNS.some((pattern) => pattern.test(trimmed))) return true;
8966
+ return false;
8967
+ }
8940
8968
  function isGenericContinuationQuery(query) {
8941
8969
  const trimmed = query.trim();
8942
8970
  if (!trimmed) return false;
@@ -8954,6 +8982,16 @@ function isShortRepairFollowUpQuery(query) {
8954
8982
  if (tokens.length > 8) return false;
8955
8983
  return SHORT_REPAIR_FOLLOW_UP_PATTERNS.some((pattern) => pattern.test(trimmed));
8956
8984
  }
8985
+ function isLowConfidenceContextFallbackQuery(query) {
8986
+ const trimmed = query.trim();
8987
+ if (!trimmed) return false;
8988
+ if (isGenericContinuationQuery(trimmed) || isShortRepairFollowUpQuery(trimmed)) return true;
8989
+ const terms = new Set(tokenizeQualityText(trimmed));
8990
+ if ((terms.has("compacted") || terms.has("compaction")) && terms.has("handoff")) return false;
8991
+ const hasContinuationRecall = /^(?:continue|resume)\b/i.test(trimmed) && (terms.has("work") || terms.has("step") || terms.has("task") || terms.has("last") || terms.has("completed"));
8992
+ 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"));
8993
+ return hasContinuationRecall || hasValidationGateRecall;
8994
+ }
8957
8995
  function isCurrentStateQuery(query) {
8958
8996
  const trimmed = query.trim();
8959
8997
  if (!trimmed) return false;
@@ -9127,6 +9165,7 @@ var Retriever = class {
9127
9165
  }
9128
9166
  async retrieve(query, options = {}) {
9129
9167
  const opts = { ...DEFAULT_OPTIONS, ...options };
9168
+ const retrievalMode = options.retrievalMode ?? ((options.strategy ?? DEFAULT_OPTIONS.strategy) === "auto" ? "session-event-hybrid" : "event");
9130
9169
  const sessionFilter = opts.scope?.sessionId ?? opts.sessionId;
9131
9170
  const fallbackTrace = [];
9132
9171
  const qualityQuery = buildRetrievalQualityQuery(query);
@@ -9157,6 +9196,7 @@ var Retriever = class {
9157
9196
  decayPolicy: opts.decayPolicy,
9158
9197
  intentRewrite: opts.intentRewrite === true,
9159
9198
  graphHop: opts.graphHop,
9199
+ retrievalMode,
9160
9200
  projectScopeMode: opts.projectScopeMode,
9161
9201
  projectHash: opts.projectHash,
9162
9202
  allowedProjectHashes: opts.allowedProjectHashes,
@@ -9175,6 +9215,7 @@ var Retriever = class {
9175
9215
  rerankWeights: opts.rerankWeights,
9176
9216
  decayPolicy: opts.decayPolicy,
9177
9217
  graphHop: opts.graphHop,
9218
+ retrievalMode,
9178
9219
  projectScopeMode: opts.projectScopeMode,
9179
9220
  projectHash: opts.projectHash,
9180
9221
  allowedProjectHashes: opts.allowedProjectHashes,
@@ -9194,6 +9235,7 @@ var Retriever = class {
9194
9235
  rerankWeights: opts.rerankWeights,
9195
9236
  decayPolicy: opts.decayPolicy,
9196
9237
  graphHop: opts.graphHop,
9238
+ retrievalMode,
9197
9239
  projectScopeMode: opts.projectScopeMode,
9198
9240
  projectHash: opts.projectHash,
9199
9241
  allowedProjectHashes: opts.allowedProjectHashes,
@@ -9214,14 +9256,37 @@ var Retriever = class {
9214
9256
  query,
9215
9257
  minScore: opts.minScore
9216
9258
  });
9259
+ const expandedSummary = retrievalMode === "session-event-hybrid" ? await this.expandSessionEventHybrid(filteredSummary, {
9260
+ query: qualityQuery,
9261
+ currentStateQuery: query,
9262
+ limit: opts.topK * 4
9263
+ }) : filteredSummary;
9264
+ const scopedExpandedSummary = retrievalMode === "session-event-hybrid" ? await this.applyScopeFilters(expandedSummary, {
9265
+ scope: opts.scope,
9266
+ projectScopeMode: opts.projectScopeMode,
9267
+ projectHash: opts.projectHash,
9268
+ allowedProjectHashes: opts.allowedProjectHashes,
9269
+ facets: opts.facets
9270
+ }) : expandedSummary;
9271
+ const finalSummary = retrievalMode === "session-event-hybrid" ? this.applyQualityFilters(scopedExpandedSummary, {
9272
+ query,
9273
+ minScore: opts.minScore
9274
+ }) : scopedExpandedSummary;
9217
9275
  current = {
9218
- results: filteredSummary,
9219
- candidateResults: filteredSummary,
9220
- matchResult: this.matcher.matchSearchResults(filteredSummary, () => 0)
9276
+ results: finalSummary,
9277
+ candidateResults: finalSummary,
9278
+ matchResult: this.matcher.matchSearchResults(finalSummary, () => 0)
9221
9279
  };
9222
9280
  fallbackTrace.push("fallback:summary");
9223
9281
  }
9224
- const memories = await this.enrichResults(current.results.slice(0, opts.topK), opts);
9282
+ const selectedResults = current.results.slice(0, opts.topK).filter((result) => {
9283
+ if (current.matchResult.confidence !== "none") return true;
9284
+ if (isLowConfidenceContextFallbackQuery(query)) {
9285
+ return (result.semanticScore ?? result.score) >= 0.5 || result.score >= 0.5;
9286
+ }
9287
+ return (result.semanticScore ?? result.score) >= 0.62 || result.score >= 0.62;
9288
+ });
9289
+ const memories = await this.enrichResults(selectedResults, opts, query);
9225
9290
  const context = this.buildContext(memories, opts.maxTokens);
9226
9291
  return {
9227
9292
  memories,
@@ -9229,7 +9294,7 @@ var Retriever = class {
9229
9294
  totalTokens: this.estimateTokens(context),
9230
9295
  context,
9231
9296
  fallbackTrace,
9232
- selectedDebug: current.results.slice(0, opts.topK).map((r) => this.debugDetailForResult(r)),
9297
+ selectedDebug: selectedResults.map((r) => this.debugDetailForResult(r)),
9233
9298
  candidateDebug: (current.candidateResults || []).slice(0, Math.max(opts.topK * 3, 20)).map((r) => this.debugDetailForResult(r)),
9234
9299
  rawQueryText: current.queryRewriteKind ? query : void 0,
9235
9300
  effectiveQueryText: current.effectiveQueryText,
@@ -9296,13 +9361,18 @@ var Retriever = class {
9296
9361
  initialResults = this.mergeResults(initialResults, rewrittenResults, input.topK * 3);
9297
9362
  }
9298
9363
  }
9299
- const expandedResults = input.graphHop?.enabled === false ? initialResults : await this.expandGraphHops(initialResults, {
9364
+ const graphExpandedResults = input.graphHop?.enabled === false ? initialResults : await this.expandGraphHops(initialResults, {
9300
9365
  query,
9301
9366
  queryGraphEnabled: this.queryGraphExpansionEnabled,
9302
9367
  maxHops: clampGraphHops(input.graphHop?.maxHops ?? 1),
9303
9368
  hopPenalty: Math.max(0, input.graphHop?.hopPenalty ?? 0.08),
9304
9369
  limit: input.topK * 4
9305
9370
  });
9371
+ const expandedResults = input.retrievalMode === "session-event-hybrid" ? await this.expandSessionEventHybrid(graphExpandedResults, {
9372
+ query: rerankQuery,
9373
+ currentStateQuery: query,
9374
+ limit: input.topK * 4
9375
+ }) : graphExpandedResults;
9306
9376
  const rerankedResults = input.rerankWithKeyword ? this.rerankByKeywordOverlap(expandedResults, rerankQuery, input.rerankWeights, input.decayPolicy) : expandedResults;
9307
9377
  const filtered = await this.applyScopeFilters(rerankedResults, {
9308
9378
  scope: input.scope,
@@ -9324,6 +9394,7 @@ var Retriever = class {
9324
9394
  if (isCurrentStateQuery(options.query)) {
9325
9395
  filtered = filtered.filter((result) => !isStaleOrSupersededContent(result.content));
9326
9396
  }
9397
+ filtered = filtered.filter((result) => !isLowSignalContextContent(result.content));
9327
9398
  filtered = filtered.filter(
9328
9399
  (result) => this.isGraphPathResult(result) || hasDiscriminativeTermOverlap(options.query, result.content)
9329
9400
  );
@@ -9349,6 +9420,47 @@ var Retriever = class {
9349
9420
  }
9350
9421
  return [...byId.values()].sort((a, b) => b.score - a.score).slice(0, limit);
9351
9422
  }
9423
+ async expandSessionEventHybrid(seeds, opts) {
9424
+ if (seeds.length === 0 || opts.limit <= seeds.length) return seeds;
9425
+ const queryTokens = this.tokenize(opts.query);
9426
+ if (queryTokens.length === 0) return seeds;
9427
+ const byId = /* @__PURE__ */ new Map();
9428
+ for (const seed of seeds) byId.set(seed.eventId, seed);
9429
+ const bestSeedBySession = /* @__PURE__ */ new Map();
9430
+ for (const seed of [...seeds].sort((a, b) => b.score - a.score || compareStable(a.eventId, b.eventId))) {
9431
+ if (!seed.sessionId || bestSeedBySession.has(seed.sessionId)) continue;
9432
+ bestSeedBySession.set(seed.sessionId, seed);
9433
+ }
9434
+ const suppressStaleState = isCurrentStateQuery(opts.currentStateQuery);
9435
+ for (const [sessionId, seed] of bestSeedBySession) {
9436
+ const sessionEvents = await this.eventStore.getSessionEvents(sessionId);
9437
+ for (const event of [...sessionEvents].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime())) {
9438
+ if (byId.has(event.id)) continue;
9439
+ if (isLowSignalContextContent(event.content)) continue;
9440
+ if (suppressStaleState && isStaleOrSupersededContent(event.content)) continue;
9441
+ const lexicalScore = this.keywordOverlap(queryTokens, this.tokenize(event.content));
9442
+ if (lexicalScore <= 0) continue;
9443
+ if (shouldApplyTechnicalGuard(opts.query) && !hasTechnicalTermOverlap(opts.query, event.content)) continue;
9444
+ const score = Math.min(0.95, Math.max(0.35, seed.score * 0.72 + lexicalScore * 0.28));
9445
+ const row = withRetrievalLane({
9446
+ id: `session-event-${seed.eventId}-${event.id}`,
9447
+ eventId: event.id,
9448
+ content: event.content,
9449
+ score,
9450
+ sessionId: event.sessionId,
9451
+ eventType: event.eventType,
9452
+ timestamp: event.timestamp.toISOString(),
9453
+ semanticScore: seed.semanticScore ?? seed.score,
9454
+ lexicalScore,
9455
+ recencyScore: seed.recencyScore
9456
+ }, { lane: "session_event", reason: `same_session:${seed.eventId}`, score });
9457
+ byId.set(row.eventId, row);
9458
+ if (byId.size >= opts.limit) break;
9459
+ }
9460
+ if (byId.size >= opts.limit) break;
9461
+ }
9462
+ return [...byId.values()].sort((a, b) => b.score - a.score || compareStable(a.eventId, b.eventId)).slice(0, opts.limit);
9463
+ }
9352
9464
  async expandGraphHops(seeds, opts) {
9353
9465
  const byId = /* @__PURE__ */ new Map();
9354
9466
  for (const s of seeds) byId.set(s.eventId, s);
@@ -9664,7 +9776,7 @@ var Retriever = class {
9664
9776
  async retrieveRecent(limit = 100) {
9665
9777
  return this.eventStore.getRecentEvents(limit);
9666
9778
  }
9667
- async enrichResults(results, options) {
9779
+ async enrichResults(results, options, query) {
9668
9780
  const memories = [];
9669
9781
  for (const result of results) {
9670
9782
  const event = await this.eventStore.getEvent(result.eventId);
@@ -9674,13 +9786,13 @@ var Retriever = class {
9674
9786
  }
9675
9787
  let sessionContext;
9676
9788
  if (options.includeSessionContext) {
9677
- sessionContext = await this.getSessionContext(event.sessionId, event.id);
9789
+ sessionContext = await this.getSessionContext(event.sessionId, event.id, query);
9678
9790
  }
9679
9791
  memories.push({ event, score: result.score, sessionContext });
9680
9792
  }
9681
9793
  return memories;
9682
9794
  }
9683
- async getSessionContext(sessionId, eventId) {
9795
+ async getSessionContext(sessionId, eventId, query) {
9684
9796
  const sessionEvents = await this.eventStore.getSessionEvents(sessionId);
9685
9797
  const eventIndex = sessionEvents.findIndex((e) => e.id === eventId);
9686
9798
  if (eventIndex === -1) return void 0;
@@ -9688,7 +9800,9 @@ var Retriever = class {
9688
9800
  const end = Math.min(sessionEvents.length, eventIndex + 2);
9689
9801
  const contextEvents = sessionEvents.slice(start, end);
9690
9802
  if (contextEvents.length <= 1) return void 0;
9691
- return contextEvents.filter((e) => e.id !== eventId).map((e) => `[${e.eventType}]: ${e.content.slice(0, 200)}...`).join("\n");
9803
+ const suppressStaleState = isCurrentStateQuery(query);
9804
+ 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)}...`);
9805
+ return contextLines.length > 0 ? contextLines.join("\n") : void 0;
9692
9806
  }
9693
9807
  buildUnifiedContext(projectResult, sharedMemories) {
9694
9808
  let context = projectResult.context;