Class: Llmemory::LongTerm::Procedural::Memory
- Inherits:
-
Object
- Object
- Llmemory::LongTerm::Procedural::Memory
- Includes:
- MemoryModule
- Defined in:
- lib/llmemory/long_term/procedural/memory.rb
Overview
Procedural long-term memory: a Voyager-style skill library. Agents register reusable skills (prompts, templates, code), retrieve them by relevance to the current task, and report outcomes so proven skills are preferred over unproven ones.
The success rate of each skill is surfaced as importance, so the
retrieval Engine ranks battle-tested skills higher (P3). Semantic
(embedding) retrieval is opt-in via config.procedural_vector_enabled or
by injecting a vector_store:; when off, search is keyword-only.
Constant Summary collapse
- KEYWORD_MATCH_SCORE =
Retrieval Engine integration: skills ranked by relevance, recency and proven utility (success rate exposed as importance). Hybrid (vector + keyword) when a vector store is active; otherwise keyword-only.
0.6
Instance Attribute Summary collapse
-
#storage ⇒ Object
readonly
Returns the value of attribute storage.
-
#user_id ⇒ Object
readonly
Returns the value of attribute user_id.
Instance Method Summary collapse
- #count ⇒ Object
-
#expired_ids(cutoff:) ⇒ Object
Storage accessor for the TTL maintenance job.
- #find_skill(query) ⇒ Object
- #forget(ids:, reason: nil, mode: :soft) ⇒ Object
- #get_skill(id) ⇒ Object
-
#initialize(user_id:, storage: nil, vector_store: nil, cipher: nil, forget_log_store: nil) ⇒ Memory
constructor
A new instance of Memory.
- #list(user_id: nil, limit: nil, offset: nil) ⇒ Object
-
#register_skill(name:, body:, description: nil, kind: Skill::DEFAULT_KIND, version: nil, provenance: nil) ⇒ Object
Registers a skill.
-
#report_outcome(skill_id, success:) ⇒ Object
Records that applying a skill succeeded or failed.
- #search_candidates(query, user_id: nil, top_k: 20) ⇒ Object
- #skills(limit: nil, offset: nil) ⇒ Object
- #stats(user_id: nil) ⇒ Object
-
#write(name:, body:, description: nil, kind: Skill::DEFAULT_KIND, version: nil, provenance: nil, **_meta) ⇒ Object
--- MemoryModule uniform interface ---.
Methods included from MemoryModule
#forget_log, #forget_log_store, #read
Constructor Details
#initialize(user_id:, storage: nil, vector_store: nil, cipher: nil, forget_log_store: nil) ⇒ Memory
Returns a new instance of Memory.
25 26 27 28 29 30 31 32 |
# File 'lib/llmemory/long_term/procedural/memory.rb', line 25 def initialize(user_id:, storage: nil, vector_store: nil, cipher: nil, forget_log_store: nil) @user_id = user_id @cipher = cipher || Llmemory.build_cipher @forget_log_store = forget_log_store @storage = storage || Storages.build(cipher: @cipher) @vector_store = vector_store @vector_explicit = !vector_store.nil? end |
Instance Attribute Details
#storage ⇒ Object (readonly)
Returns the value of attribute storage.
23 24 25 |
# File 'lib/llmemory/long_term/procedural/memory.rb', line 23 def storage @storage end |
#user_id ⇒ Object (readonly)
Returns the value of attribute user_id.
23 24 25 |
# File 'lib/llmemory/long_term/procedural/memory.rb', line 23 def user_id @user_id end |
Instance Method Details
#count ⇒ Object
61 62 63 |
# File 'lib/llmemory/long_term/procedural/memory.rb', line 61 def count @storage.count_skills(@user_id) end |
#expired_ids(cutoff:) ⇒ Object
Storage accessor for the TTL maintenance job.
120 121 122 |
# File 'lib/llmemory/long_term/procedural/memory.rb', line 120 def expired_ids(cutoff:) @storage.expired_skill_ids(@user_id, cutoff: cutoff) end |
#find_skill(query) ⇒ Object
47 48 49 50 |
# File 'lib/llmemory/long_term/procedural/memory.rb', line 47 def find_skill(query) raw = @storage.search_skills(@user_id, query).first raw && Skill.from_h(raw) end |
#forget(ids:, reason: nil, mode: :soft) ⇒ Object
106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/llmemory/long_term/procedural/memory.rb', line 106 def forget(ids:, reason: nil, mode: :soft) requested = Array(ids).map(&:to_s) existing = @storage.list_skills(@user_id).map { |s| (s[:id] || s["id"]).to_s } targeted = requested & existing count = case mode when :hard then @storage.delete_skills(@user_id, targeted).to_i else @storage.archive_skills(@user_id, targeted).to_i end forget_log.record(@user_id, memory_type: "procedural", ids: targeted, reason: reason) Llmemory::Instrumentation.instrument(:memory_forget, memory_type: "procedural", user_id: @user_id, count: count, mode: mode) count end |
#get_skill(id) ⇒ Object
52 53 54 55 |
# File 'lib/llmemory/long_term/procedural/memory.rb', line 52 def get_skill(id) raw = @storage.get_skill(@user_id, id) raw && Skill.from_h(raw) end |
#list(user_id: nil, limit: nil, offset: nil) ⇒ Object
98 99 100 |
# File 'lib/llmemory/long_term/procedural/memory.rb', line 98 def list(user_id: nil, limit: nil, offset: nil) skills(limit: limit, offset: offset) end |
#register_skill(name:, body:, description: nil, kind: Skill::DEFAULT_KIND, version: nil, provenance: nil) ⇒ Object
Registers a skill. If version is omitted and a skill with the same
name exists, the version auto-increments (skill evolution).
36 37 38 39 40 41 42 43 44 45 |
# File 'lib/llmemory/long_term/procedural/memory.rb', line 36 def register_skill(name:, body:, description: nil, kind: Skill::DEFAULT_KIND, version: nil, provenance: nil) version ||= next_version_for(name) skill = Skill.new( id: nil, user_id: @user_id, name: name, body: body, description: description, kind: kind, version: version, provenance: provenance ) id = @storage.save_skill(@user_id, skill.to_h) index_vector(id, skill.searchable_text) id end |
#report_outcome(skill_id, success:) ⇒ Object
Records that applying a skill succeeded or failed. Feeds retrieval ranking and adaptive retrieval (P8). Returns the updated Skill.
67 68 69 70 |
# File 'lib/llmemory/long_term/procedural/memory.rb', line 67 def report_outcome(skill_id, success:) raw = @storage.record_outcome(@user_id, skill_id, success: success) raw && Skill.from_h(raw) end |
#search_candidates(query, user_id: nil, top_k: 20) ⇒ Object
77 78 79 80 81 82 83 84 85 86 |
# File 'lib/llmemory/long_term/procedural/memory.rb', line 77 def search_candidates(query, user_id: nil, top_k: 20) uid = user_id || @user_id return [] unless uid == @user_id keyword = @storage.search_skills(uid, query).first(top_k).map { |raw| candidate_for(raw, KEYWORD_MATCH_SCORE) } vs = vector_store return keyword unless vs merge_candidates(vector_candidates(query, top_k, vs), keyword, top_k) end |
#skills(limit: nil, offset: nil) ⇒ Object
57 58 59 |
# File 'lib/llmemory/long_term/procedural/memory.rb', line 57 def skills(limit: nil, offset: nil) @storage.list_skills(@user_id, limit: limit, offset: offset).map { |s| Skill.from_h(s) } end |
#stats(user_id: nil) ⇒ Object
102 103 104 |
# File 'lib/llmemory/long_term/procedural/memory.rb', line 102 def stats(user_id: nil) { skills: count } end |
#write(name:, body:, description: nil, kind: Skill::DEFAULT_KIND, version: nil, provenance: nil, **_meta) ⇒ Object
--- MemoryModule uniform interface ---
90 91 92 93 94 95 96 |
# File 'lib/llmemory/long_term/procedural/memory.rb', line 90 def write(name:, body:, description: nil, kind: Skill::DEFAULT_KIND, version: nil, provenance: nil, **) result = nil Llmemory::Instrumentation.instrument(:memory_write, memory_type: "procedural", user_id: @user_id) do result = register_skill(name: name, body: body, description: description, kind: kind, version: version, provenance: provenance) end result end |