Class: ClaudeMemory::Recall::LegacyEngine

Inherits:
Object
  • Object
show all
Includes:
QueryCore
Defined in:
lib/claude_memory/recall/legacy_engine.rb

Overview

Query engine for legacy single-store mode. Operates directly on one SQLiteStore with local scope filtering.

Instance Method Summary collapse

Constructor Details

#initialize(store, fts:, embedding_generator:, project_path:) ⇒ LegacyEngine

Returns a new instance of LegacyEngine.



10
11
12
13
14
15
# File 'lib/claude_memory/recall/legacy_engine.rb', line 10

def initialize(store, fts:, embedding_generator:, project_path:)
  @store = store
  @fts = fts
  @embedding_generator = embedding_generator
  @project_path = project_path
end

Instance Method Details

#changes(since:, limit:, scope:) ⇒ Object



92
93
94
95
96
97
98
99
100
101
# File 'lib/claude_memory/recall/legacy_engine.rb', line 92

def changes(since:, limit:, scope:)
  ds = @store.facts
    .select(:id, :docid, :subject_entity_id, :predicate, :object_literal, :status, :created_at, :scope, :project_path)
    .where { created_at >= since }
    .order(Sequel.desc(:created_at))
    .limit(limit)

  ds = apply_scope_filter(ds, scope)
  ds.all
end

#conflicts(scope:) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
# File 'lib/claude_memory/recall/legacy_engine.rb', line 103

def conflicts(scope:)
  all_conflicts = @store.open_conflicts
  return all_conflicts if scope == SCOPE_ALL

  all_conflicts.select do |conflict|
    fact_a = Core::FactQueryBuilder.find_fact(@store, conflict[:fact_a_id])
    fact_b = Core::FactQueryBuilder.find_fact(@store, conflict[:fact_b_id])

    fact_matches_scope?(fact_a, scope) || fact_matches_scope?(fact_b, scope)
  end
end

#explain(fact_id_or_docid, scope:) ⇒ Object



87
88
89
90
# File 'lib/claude_memory/recall/legacy_engine.rb', line 87

def explain(fact_id_or_docid, scope:)
  fact_id = resolve_fact_identifier(@store, fact_id_or_docid)
  explain_from_store(@store, fact_id)
end

#fact_graph(fact_id, depth:, scope:) ⇒ Object



83
84
85
# File 'lib/claude_memory/recall/legacy_engine.rb', line 83

def fact_graph(fact_id, depth:, scope:)
  Core::FactGraph.build(@store, fact_id, depth: depth)
end

#facts_by_branch(branch_name, limit:, scope:) ⇒ Object



115
116
117
# File 'lib/claude_memory/recall/legacy_engine.rb', line 115

def facts_by_branch(branch_name, limit:, scope:)
  facts_by_context_single(@store, :git_branch, branch_name, limit: limit, source: :legacy)
end

#facts_by_directory(cwd, limit:, scope:) ⇒ Object



119
120
121
# File 'lib/claude_memory/recall/legacy_engine.rb', line 119

def facts_by_directory(cwd, limit:, scope:)
  facts_by_context_single(@store, :cwd, cwd, limit: limit, source: :legacy)
end

#facts_by_tool(tool_name, limit:, scope:) ⇒ Object



123
124
125
# File 'lib/claude_memory/recall/legacy_engine.rb', line 123

def facts_by_tool(tool_name, limit:, scope:)
  facts_by_tool_single(@store, tool_name, limit: limit, source: :legacy)
end

#query(query_text, limit:, scope:, include_raw_text: false, intent: nil) ⇒ Object



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/claude_memory/recall/legacy_engine.rb', line 17

def query(query_text, limit:, scope:, include_raw_text: false, intent: nil)
  effective_query = intent_augmented_query(query_text, intent)
  content_ids = @fts.search(effective_query, limit: limit * 3)
  return [] if content_ids.empty?

  provenance_by_content = @store.provenance
    .select(:fact_id, :content_item_id)
    .where(content_item_id: content_ids)
    .all
    .group_by { |p| p[:content_item_id] }

  all_fact_ids = []
  seen_fact_ids = Set.new
  content_ids.each do |content_id|
    (provenance_by_content[content_id] || []).each do |prov|
      next if seen_fact_ids.include?(prov[:fact_id])
      seen_fact_ids.add(prov[:fact_id])
      all_fact_ids << prov[:fact_id]
    end
  end

  return [] if all_fact_ids.empty?

  facts_by_id = batch_find_facts(@store, all_fact_ids)

  selected_fact_ids = []
  all_fact_ids.each do |fact_id|
    fact = facts_by_id[fact_id]
    next unless fact
    next unless fact_matches_scope?(fact, scope)
    selected_fact_ids << fact_id
    break if selected_fact_ids.size >= limit
  end

  return [] if selected_fact_ids.empty?

  receipts_by_fact_id = batch_find_receipts(@store, selected_fact_ids)

  facts_with_provenance = selected_fact_ids.map do |fact_id|
    {
      fact: facts_by_id[fact_id],
      receipts: receipts_by_fact_id[fact_id] || []
    }
  end

  sort_by_scope_priority(facts_with_provenance)
end

#query_concepts(concepts, limit:, scope:) ⇒ Object



133
134
135
# File 'lib/claude_memory/recall/legacy_engine.rb', line 133

def query_concepts(concepts, limit:, scope:)
  query_concepts_single(@store, concepts, limit: limit, source: :legacy)
end

#query_index(query_text, limit:, scope:, intent: nil) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/claude_memory/recall/legacy_engine.rb', line 65

def query_index(query_text, limit:, scope:, intent: nil)
  effective_query = intent_augmented_query(query_text, intent)
  options = Index::QueryOptions.new(
    query_text: effective_query,
    limit: limit,
    scope: :all,
    source: :legacy
  )

  query = Index::IndexQuery.new(@store, options)
  results = query.execute

  results.select do |result|
    fact = Core::FactQueryBuilder.find_fact(@store, result[:id])
    fact && fact_matches_scope?(fact, scope)
  end
end

#query_semantic(text, limit:, scope:, mode:, explain: false, intent: nil) ⇒ Object



127
128
129
130
131
# File 'lib/claude_memory/recall/legacy_engine.rb', line 127

def query_semantic(text, limit:, scope:, mode:, explain: false, intent: nil)
  effective_text = intent_augmented_query(text, intent)
  query_semantic_single(@store, effective_text, limit: limit, mode: mode, source: :legacy, explain: explain,
    skip_fts_shortcut: !intent.nil?)
end