Class: Engram::Memory

Inherits:
Object
  • Object
show all
Defined in:
lib/engram/memory.rb

Overview

The friendly facade. Bound to one scope (an owner), it wires the configured store and embedder into the use cases. This is what user.memory returns in Rails.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(scope:, store: Engram.config.store, embedder: Engram.config.embedder) ⇒ Memory

Returns a new instance of Memory.



9
10
11
12
13
# File 'lib/engram/memory.rb', line 9

def initialize(scope:, store: Engram.config.store, embedder: Engram.config.embedder)
  @scope = scope
  @store = store
  @embedder = embedder
end

Instance Attribute Details

#scopeObject (readonly)

Returns the value of attribute scope.



7
8
9
# File 'lib/engram/memory.rb', line 7

def scope
  @scope
end

Instance Method Details

#add(content, kind: :fact, importance: 1.0, metadata: {}) ⇒ Object

Persist a memory record of the given kind. Returns nil when the configured persistence policy rejects the record.



17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/engram/memory.rb', line 17

def add(content, kind: :fact, importance: 1.0, metadata: {})
  Engram::Instrumentation.instrument("add", Engram::Instrumentation.payload(scope: scope, store: @store, kind: kind)) do
    embedding = @embedder.embed(content)
    record = Record.new(
      content: content,
      scope: scope,
      embedding: embedding,
      kind: kind,
      importance: importance,
      metadata: 
    )
    persist(record)
  end
end

#allObject



85
86
87
# File 'lib/engram/memory.rb', line 85

def all
  @store.all(scope: scope)
end

#forget_stale(older_than:, min_importance: Float::INFINITY) ⇒ Object

Prune stale memories. older_than is a duration in seconds; min_importance keeps memories at or above that importance even when old. Returns the forgotten records.



102
103
104
105
# File 'lib/engram/memory.rb', line 102

def forget_stale(older_than:, min_importance: Float::INFINITY)
  UseCases::Forget.new(store: @store)
    .call(scope: scope, older_than: older_than, min_importance: min_importance)
end

#inject_into(prompt, query:, limit: Engram.config.default_limit, kinds: nil) ⇒ Object

Recall, then inject into a prompt string.



45
46
47
48
# File 'lib/engram/memory.rb', line 45

def inject_into(prompt, query:, limit: Engram.config.default_limit, kinds: nil)
  memories = recall(query, limit: limit, kinds: kinds)
  UseCases::Inject.new.call(prompt: prompt, memories: memories)
end

#observe(messages, completion: Engram.config.completion) ⇒ Object

Derive memories from a conversation turn and consolidate them (v0.2). messages is an Array of content: hashes (or plain strings). Returns the Array applied. Requires a configured Completion.



53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/engram/memory.rb', line 53

def observe(messages, completion: Engram.config.completion)
  if completion.nil?
    raise Engram::Error, "observe requires a Completion. Set Engram.config.completion."
  end

  UseCases::Observe.new(
    store: @store,
    extractor: build_extractor(completion),
    consolidator: build_consolidator(completion),
    processed_turns: Engram.config.processed_turns,
    embedder: @embedder
  ).call(
    messages: messages,
    scope: scope,
    idempotency_key: TurnDigest.digest(scope: scope, messages: messages)
  )
end

#observe_later(messages) ⇒ Object

Enqueue observation as a background job (Rails only).



72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/engram/memory.rb', line 72

def observe_later(messages)
  unless defined?(Engram::ObserveJob)
    raise Engram::Error, "observe_later needs ActiveJob (Rails). Use #observe outside Rails."
  end

  Engram::Instrumentation.instrument(
    "observe_later",
    Engram::Instrumentation.payload(scope: scope, store: @store, message_count: messages.size)
  ) do
    Engram::ObserveJob.perform_later(scope, messages)
  end
end

#rebuild_embeddings(stale_only: true, batch_size: 100) ⇒ Object

Recompute embeddings (and embedding metadata) for memories in the scope. When stale_only is true, only records whose current metadata does not match the active embedder are rebuilt.



92
93
94
95
96
97
98
# File 'lib/engram/memory.rb', line 92

def rebuild_embeddings(stale_only: true, batch_size: 100)
  UseCases::RebuildEmbeddings.new(store: @store, embedder: @embedder).call(
    scope: scope,
    stale_only: stale_only,
    batch_size: batch_size
  )
end

#recall(query, limit: Engram.config.default_limit, kinds: nil) ⇒ Object

Return the most relevant memories for a query.



33
34
35
36
37
38
39
40
41
42
# File 'lib/engram/memory.rb', line 33

def recall(query, limit: Engram.config.default_limit, kinds: nil)
  UseCases::Recall.new(
    store: @store,
    embedder: @embedder,
    importance_weight: Engram.config.importance_weight,
    recency_weight: Engram.config.recency_weight,
    recency_halflife: Engram.config.recency_halflife,
    touch: Engram.config.touch_on_recall
  ).call(query, scope: scope, limit: limit, kinds: kinds)
end