Class: Llmemory::LongTerm::Episodic::Memory

Inherits:
Object
  • Object
show all
Defined in:
lib/llmemory/long_term/episodic/memory.rb

Overview

Episodic long-term memory: records agent trajectories and retrieves them by recency, importance and relevance. Designed to coexist with semantic memory (file/graph), not replace it, and to feed reflection (P2), which distills episodes into semantic knowledge.

Deliberately LLM-free: recording and retrieval are deterministic. Higher order summarization belongs to reflection.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(user_id:, storage: nil) ⇒ Memory

Returns a new instance of Memory.



19
20
21
22
# File 'lib/llmemory/long_term/episodic/memory.rb', line 19

def initialize(user_id:, storage: nil)
  @user_id = user_id
  @storage = storage || Storages.build
end

Instance Attribute Details

#storageObject (readonly)

Returns the value of attribute storage.



17
18
19
# File 'lib/llmemory/long_term/episodic/memory.rb', line 17

def storage
  @storage
end

#user_idObject (readonly)

Returns the value of attribute user_id.



17
18
19
# File 'lib/llmemory/long_term/episodic/memory.rb', line 17

def user_id
  @user_id
end

Instance Method Details

#countObject



55
56
57
# File 'lib/llmemory/long_term/episodic/memory.rb', line 55

def count
  @storage.count_episodes(@user_id)
end

#episodes(limit: nil) ⇒ Object



46
47
48
# File 'lib/llmemory/long_term/episodic/memory.rb', line 46

def episodes(limit: nil)
  @storage.list_episodes(@user_id, limit: limit).map { |e| Episode.from_h(e) }
end

#find_episode(id) ⇒ Object



50
51
52
53
# File 'lib/llmemory/long_term/episodic/memory.rb', line 50

def find_episode(id)
  raw = @storage.get_episode(@user_id, id)
  raw && Episode.from_h(raw)
end

#recent_episodes(limit: 10) ⇒ Object



42
43
44
# File 'lib/llmemory/long_term/episodic/memory.rb', line 42

def recent_episodes(limit: 10)
  @storage.list_episodes(@user_id, limit: limit).map { |e| Episode.from_h(e) }
end

#record_episode(steps:, summary: nil, outcome: nil, importance: 0.5) ⇒ Object

Records a trajectory. ‘steps` is an array of hashes with any of :observation, :action, :result, :timestamp. Returns the episode id.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/llmemory/long_term/episodic/memory.rb', line 26

def record_episode(steps:, summary: nil, outcome: nil, importance: 0.5)
  episode = Episode.new(
    id: nil,
    user_id: @user_id,
    steps: steps,
    summary: summary || derive_summary(steps),
    outcome: outcome,
    importance: importance
  )
  provenance = Llmemory::Provenance.from_text_fingerprint(
    episode.searchable_text, method: "episode_recording", confidence: episode.importance
  )
  record = episode.to_h.merge(provenance: provenance)
  @storage.save_episode(@user_id, record)
end

#search_candidates(query, user_id: nil, top_k: 20) ⇒ Object

Retrieval Engine integration. Returns candidates shaped like the other long-term memories so the Engine can rank episodes by relevance, recency (temporal decay) and importance (P3), with provenance (P10).



62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/llmemory/long_term/episodic/memory.rb', line 62

def search_candidates(query, user_id: nil, top_k: 20)
  uid = user_id || @user_id
  return [] unless uid == @user_id

  @storage.search_episodes(uid, query).first(top_k).map do |e|
    episode = Episode.from_h(e)
    {
      text: episode.summary.to_s.empty? ? episode.searchable_text : episode.summary,
      timestamp: episode.created_at,
      score: 1.0,
      importance: episode.importance,
      evergreen: false,
      provenance: e[:provenance] || e["provenance"]
    }
  end
end