llmemory 0.2.0 → 0.2.2
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.
- checksums.yaml +4 -4
- data/README.md +54 -3
- data/app/controllers/llmemory/dashboard/application_controller.rb +15 -1
- data/app/controllers/llmemory/dashboard/episodic_controller.rb +22 -0
- data/app/controllers/llmemory/dashboard/forget_log_controller.rb +12 -0
- data/app/controllers/llmemory/dashboard/maintenance_controller.rb +92 -0
- data/app/controllers/llmemory/dashboard/procedural_controller.rb +22 -0
- data/app/controllers/llmemory/dashboard/reflection_controller.rb +37 -0
- data/app/controllers/llmemory/dashboard/working_controller.rb +14 -0
- data/app/views/llmemory/dashboard/episodic/index.html.erb +37 -0
- data/app/views/llmemory/dashboard/forget_log/show.html.erb +23 -0
- data/app/views/llmemory/dashboard/maintenance/show.html.erb +65 -0
- data/app/views/llmemory/dashboard/procedural/index.html.erb +38 -0
- data/app/views/llmemory/dashboard/reflection/show.html.erb +29 -0
- data/app/views/llmemory/dashboard/users/show.html.erb +16 -0
- data/app/views/llmemory/dashboard/working/show.html.erb +20 -0
- data/config/routes.rb +14 -0
- data/lib/generators/llmemory/install/templates/create_llmemory_tables.rb +22 -0
- data/lib/llmemory/cli/commands/base.rb +8 -0
- data/lib/llmemory/cli/commands/episodic.rb +42 -0
- data/lib/llmemory/cli/commands/forget_log.rb +36 -0
- data/lib/llmemory/cli/commands/maintain.rb +62 -0
- data/lib/llmemory/cli/commands/mine_skills.rb +50 -0
- data/lib/llmemory/cli/commands/procedural.rb +44 -0
- data/lib/llmemory/cli/commands/working.rb +31 -0
- data/lib/llmemory/cli.rb +18 -0
- data/lib/llmemory/configuration.rb +11 -1
- data/lib/llmemory/instrumentation.rb +33 -0
- data/lib/llmemory/llm/anthropic.rb +19 -15
- data/lib/llmemory/llm/openai.rb +16 -12
- data/lib/llmemory/long_term/episodic/memory.rb +94 -26
- data/lib/llmemory/long_term/episodic/storage.rb +7 -5
- data/lib/llmemory/long_term/episodic/storages/active_record_models.rb +17 -0
- data/lib/llmemory/long_term/episodic/storages/active_record_storage.rb +103 -0
- data/lib/llmemory/long_term/episodic/storages/base.rb +15 -2
- data/lib/llmemory/long_term/episodic/storages/database_storage.rb +156 -0
- data/lib/llmemory/long_term/episodic/storages/file_storage.rb +28 -8
- data/lib/llmemory/long_term/episodic/storages/memory_storage.rb +36 -6
- data/lib/llmemory/long_term/file_based/memory.rb +12 -4
- data/lib/llmemory/long_term/file_based/storages/active_record_storage.rb +15 -6
- data/lib/llmemory/long_term/file_based/storages/base.rb +2 -2
- data/lib/llmemory/long_term/file_based/storages/database_storage.rb +20 -8
- data/lib/llmemory/long_term/file_based/storages/file_storage.rb +6 -6
- data/lib/llmemory/long_term/file_based/storages/memory_storage.rb +6 -6
- data/lib/llmemory/long_term/graph_based/memory.rb +89 -64
- data/lib/llmemory/long_term/graph_based/storages/active_record_storage.rb +4 -2
- data/lib/llmemory/long_term/graph_based/storages/base.rb +2 -2
- data/lib/llmemory/long_term/graph_based/storages/memory_storage.rb +4 -2
- data/lib/llmemory/long_term/procedural/memory.rb +97 -30
- data/lib/llmemory/long_term/procedural/skill.rb +6 -2
- data/lib/llmemory/long_term/procedural/storage.rb +7 -5
- data/lib/llmemory/long_term/procedural/storages/active_record_models.rb +17 -0
- data/lib/llmemory/long_term/procedural/storages/active_record_storage.rb +114 -0
- data/lib/llmemory/long_term/procedural/storages/base.rb +14 -1
- data/lib/llmemory/long_term/procedural/storages/database_storage.rb +169 -0
- data/lib/llmemory/long_term/procedural/storages/file_storage.rb +29 -9
- data/lib/llmemory/long_term/procedural/storages/memory_storage.rb +37 -7
- data/lib/llmemory/maintenance/cognitive_pass.rb +109 -0
- data/lib/llmemory/maintenance/ttl_expiry.rb +50 -0
- data/lib/llmemory/maintenance.rb +2 -0
- data/lib/llmemory/mcp/server.rb +17 -1
- data/lib/llmemory/mcp/tools/memory_episode_record.rb +48 -0
- data/lib/llmemory/mcp/tools/memory_episodes.rb +43 -0
- data/lib/llmemory/mcp/tools/memory_forget.rb +53 -0
- data/lib/llmemory/mcp/tools/memory_maintain.rb +53 -0
- data/lib/llmemory/mcp/tools/memory_mine_skills.rb +53 -0
- data/lib/llmemory/mcp/tools/memory_retrieve.rb +10 -2
- data/lib/llmemory/mcp/tools/memory_skill_register.rb +35 -0
- data/lib/llmemory/mcp/tools/memory_skill_report.rb +35 -0
- data/lib/llmemory/mcp/tools/memory_skills.rb +43 -0
- data/lib/llmemory/memory.rb +48 -3
- data/lib/llmemory/memory_module.rb +13 -6
- data/lib/llmemory/reflection/reflector.rb +24 -20
- data/lib/llmemory/retrieval/bm25_scorer.rb +1 -1
- data/lib/llmemory/retrieval/engine.rb +25 -16
- data/lib/llmemory/retrieval/mmr_reranker.rb +1 -1
- data/lib/llmemory/short_term/session_lifecycle.rb +19 -3
- data/lib/llmemory/skill_mining/miner.rb +163 -0
- data/lib/llmemory/skill_mining.rb +8 -0
- data/lib/llmemory/tokenizer.rb +27 -0
- data/lib/llmemory/vector_store/active_record_store.rb +4 -3
- data/lib/llmemory/vector_store/openai_embeddings.rb +11 -7
- data/lib/llmemory/vector_store.rb +14 -0
- data/lib/llmemory/version.rb +1 -1
- data/lib/llmemory.rb +3 -0
- metadata +39 -1
|
@@ -5,6 +5,18 @@ require_relative "stores"
|
|
|
5
5
|
module Llmemory
|
|
6
6
|
module ShortTerm
|
|
7
7
|
class SessionLifecycle
|
|
8
|
+
# Pseudo-sessions used by ForgetLog, FeedbackStore and WorkingMemory share
|
|
9
|
+
# the short-term K/V store but are not user sessions — they must not be
|
|
10
|
+
# idle-pruned, stale-pruned, or evicted by enforce_max_entries.
|
|
11
|
+
PSEUDO_SESSION_PATTERNS = [
|
|
12
|
+
/\A__[a-z_]+__\z/, # e.g. "__forget_log__", "__retrieval_feedback__"
|
|
13
|
+
/:working_memory\z/ # WorkingMemory uses "<session>:working_memory"
|
|
14
|
+
].freeze
|
|
15
|
+
|
|
16
|
+
def self.pseudo_session?(session_id)
|
|
17
|
+
PSEUDO_SESSION_PATTERNS.any? { |p| session_id.to_s.match?(p) }
|
|
18
|
+
end
|
|
19
|
+
|
|
8
20
|
def initialize(store: nil)
|
|
9
21
|
@store = store || build_store
|
|
10
22
|
end
|
|
@@ -14,7 +26,7 @@ module Llmemory
|
|
|
14
26
|
cutoff = Time.now - (idle_minutes * 60)
|
|
15
27
|
deleted = 0
|
|
16
28
|
|
|
17
|
-
|
|
29
|
+
user_sessions(user_id).each do |session_id|
|
|
18
30
|
state = @store.load(user_id, session_id)
|
|
19
31
|
next unless state.is_a?(Hash)
|
|
20
32
|
|
|
@@ -36,7 +48,7 @@ module Llmemory
|
|
|
36
48
|
cutoff = Time.now - (prune_after_days * 86400)
|
|
37
49
|
deleted = 0
|
|
38
50
|
|
|
39
|
-
|
|
51
|
+
user_sessions(user_id).each do |session_id|
|
|
40
52
|
state = @store.load(user_id, session_id)
|
|
41
53
|
next unless state.is_a?(Hash)
|
|
42
54
|
|
|
@@ -55,7 +67,7 @@ module Llmemory
|
|
|
55
67
|
|
|
56
68
|
def enforce_max_entries!(user_id:, max_entries: nil)
|
|
57
69
|
max_entries ||= Llmemory.configuration.session_max_entries_per_user
|
|
58
|
-
sessions =
|
|
70
|
+
sessions = user_sessions(user_id)
|
|
59
71
|
return 0 if sessions.size <= max_entries
|
|
60
72
|
|
|
61
73
|
session_ages = sessions.map do |session_id|
|
|
@@ -73,6 +85,10 @@ module Llmemory
|
|
|
73
85
|
|
|
74
86
|
private
|
|
75
87
|
|
|
88
|
+
def user_sessions(user_id)
|
|
89
|
+
@store.list_sessions(user_id: user_id).reject { |s| self.class.pseudo_session?(s) }
|
|
90
|
+
end
|
|
91
|
+
|
|
76
92
|
def build_store
|
|
77
93
|
Stores.build
|
|
78
94
|
end
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Llmemory
|
|
6
|
+
module SkillMining
|
|
7
|
+
# Skill mining scans an agent's recent episodes (episodic memory) for
|
|
8
|
+
# repeated, successful trajectories and distills them into reusable skills
|
|
9
|
+
# (procedural memory). This is Voyager's actual contribution: rather than a
|
|
10
|
+
# passive, hand-written skill library, procedural memory grows from lived
|
|
11
|
+
# experience.
|
|
12
|
+
#
|
|
13
|
+
# Mining is human-in-the-loop by default: `mine` returns skill *proposals*
|
|
14
|
+
# and writes nothing. Pass `auto_register: true` to register them directly.
|
|
15
|
+
# Each registered skill carries provenance { method: "skill_mining",
|
|
16
|
+
# sources: [{ type: "episode", id: ... }] } so it stays traceable to the
|
|
17
|
+
# experiences it was distilled from.
|
|
18
|
+
#
|
|
19
|
+
# `procedural` must respond to:
|
|
20
|
+
# register_skill(name:, body:, description:, kind:, provenance:)
|
|
21
|
+
class Miner
|
|
22
|
+
DEFAULT_WINDOW = 20
|
|
23
|
+
DEFAULT_CONFIDENCE = 0.5
|
|
24
|
+
VALID_KINDS = %w[prompt template code].freeze
|
|
25
|
+
|
|
26
|
+
def initialize(episodic:, procedural:, llm: nil)
|
|
27
|
+
@episodic = episodic
|
|
28
|
+
@procedural = procedural
|
|
29
|
+
@llm = llm || Llmemory::LLM.client
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Mines the most recent `window` episodes for reusable skills. When
|
|
33
|
+
# `outcomes` (an allowlist of outcome labels) is given, only episodes whose
|
|
34
|
+
# outcome is in the set are considered — a deterministic pre-filter.
|
|
35
|
+
#
|
|
36
|
+
# Returns an array of proposal hashes
|
|
37
|
+
# ({ name:, kind:, body:, description:, confidence: }). When
|
|
38
|
+
# `auto_register: true`, registers each proposal and returns the new skill
|
|
39
|
+
# ids instead.
|
|
40
|
+
def mine(window: DEFAULT_WINDOW, outcomes: nil, auto_register: false)
|
|
41
|
+
result = []
|
|
42
|
+
Llmemory::Instrumentation.instrument(:mine_skills, window: window, auto_register: auto_register) do
|
|
43
|
+
episodes = @episodic.recent_episodes(limit: window)
|
|
44
|
+
episodes = filter_by_outcome(episodes, outcomes) if outcomes
|
|
45
|
+
next if episodes.empty?
|
|
46
|
+
|
|
47
|
+
proposals = distill(episodes)
|
|
48
|
+
next if proposals.empty?
|
|
49
|
+
|
|
50
|
+
result = auto_register ? register(proposals, episodes) : proposals
|
|
51
|
+
end
|
|
52
|
+
result
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
private
|
|
56
|
+
|
|
57
|
+
def filter_by_outcome(episodes, outcomes)
|
|
58
|
+
allowed = Array(outcomes).map { |o| o.to_s.strip.downcase }
|
|
59
|
+
episodes.select { |ep| allowed.include?(ep.outcome.to_s.strip.downcase) }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def register(proposals, episodes)
|
|
63
|
+
sources = episodes.map(&:id).compact.map { |id| { type: "episode", id: id } }
|
|
64
|
+
proposals.map do |p|
|
|
65
|
+
provenance = Llmemory::Provenance.build(
|
|
66
|
+
method: "skill_mining",
|
|
67
|
+
sources: sources,
|
|
68
|
+
confidence: p[:confidence]
|
|
69
|
+
)
|
|
70
|
+
@procedural.register_skill(
|
|
71
|
+
name: p[:name],
|
|
72
|
+
body: p[:body],
|
|
73
|
+
description: p[:description],
|
|
74
|
+
kind: p[:kind],
|
|
75
|
+
provenance: provenance
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def distill(episodes)
|
|
81
|
+
response = @llm.invoke(build_prompt(episodes))
|
|
82
|
+
parse_proposals(response)
|
|
83
|
+
rescue Llmemory::LLMError
|
|
84
|
+
[]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def build_prompt(episodes)
|
|
88
|
+
episodes_text = episodes.each_with_index.map do |ep, i|
|
|
89
|
+
"Episode #{i + 1} (outcome: #{ep.outcome || 'n/a'}):\n#{ep.searchable_text}"
|
|
90
|
+
end.join("\n\n")
|
|
91
|
+
|
|
92
|
+
<<~PROMPT
|
|
93
|
+
You are mining an agent's recent experiences for reusable skills. A skill
|
|
94
|
+
is a repeatable procedure the agent can apply again: a prompt, a template,
|
|
95
|
+
or a snippet of code. Only propose a skill when you see a SUCCESSFUL
|
|
96
|
+
pattern that recurs across episodes — generalize the steps into a reusable
|
|
97
|
+
procedure. Do not propose one-off actions or failures.
|
|
98
|
+
|
|
99
|
+
Recent episodes:
|
|
100
|
+
#{episodes_text}
|
|
101
|
+
|
|
102
|
+
Return a JSON array of objects with keys:
|
|
103
|
+
"name" (short snake_case identifier),
|
|
104
|
+
"kind" (one of "prompt", "template", "code"),
|
|
105
|
+
"body" (the reusable procedure itself),
|
|
106
|
+
"description" (one sentence on when to apply it),
|
|
107
|
+
"confidence" (0-1).
|
|
108
|
+
Return an empty array if no reusable skill can be distilled.
|
|
109
|
+
Example: [{"name": "rollback_on_deploy_failure", "kind": "prompt",
|
|
110
|
+
"body": "When a deploy fails, roll back to the last known-good release.",
|
|
111
|
+
"description": "Recover service after a failed deploy", "confidence": 0.8}]
|
|
112
|
+
PROMPT
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def parse_proposals(response)
|
|
116
|
+
json = extract_json_array(response)
|
|
117
|
+
return [] unless json
|
|
118
|
+
|
|
119
|
+
json.filter_map do |item|
|
|
120
|
+
next nil unless item.is_a?(Hash)
|
|
121
|
+
name = (item["name"] || item[:name]).to_s.strip
|
|
122
|
+
body = (item["body"] || item[:body]).to_s.strip
|
|
123
|
+
next nil if name.empty? || body.empty?
|
|
124
|
+
|
|
125
|
+
{
|
|
126
|
+
name: name,
|
|
127
|
+
kind: normalize_kind(item["kind"] || item[:kind]),
|
|
128
|
+
body: body,
|
|
129
|
+
description: presence(item["description"] || item[:description]),
|
|
130
|
+
confidence: normalize_confidence(item["confidence"] || item[:confidence])
|
|
131
|
+
}
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def normalize_kind(value)
|
|
136
|
+
k = value.to_s.strip.downcase
|
|
137
|
+
VALID_KINDS.include?(k) ? k : "prompt"
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def normalize_confidence(value)
|
|
141
|
+
return DEFAULT_CONFIDENCE if value.nil?
|
|
142
|
+
v = value.to_f
|
|
143
|
+
v.between?(0, 1) ? v : DEFAULT_CONFIDENCE
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def presence(value)
|
|
147
|
+
s = value.to_s.strip
|
|
148
|
+
s.empty? ? nil : s
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def extract_json_array(response)
|
|
152
|
+
response = response.to_s.strip
|
|
153
|
+
start_idx = response.index("[")
|
|
154
|
+
end_idx = response.rindex("]")
|
|
155
|
+
return nil unless start_idx && end_idx
|
|
156
|
+
|
|
157
|
+
JSON.parse(response[start_idx..end_idx])
|
|
158
|
+
rescue JSON::ParserError
|
|
159
|
+
nil
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Llmemory
|
|
4
|
+
# Shared word tokenizer for keyword search and lexical scoring (BM25, MMR).
|
|
5
|
+
# Centralizes the tokenization regex that was duplicated across the codebase.
|
|
6
|
+
module Tokenizer
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
WORD = /\b[a-z0-9]{2,}\b/
|
|
10
|
+
|
|
11
|
+
def tokenize(text)
|
|
12
|
+
text.to_s.downcase.scan(WORD)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Lexical match used by storage-level keyword search. A query is split into
|
|
16
|
+
# tokens and matched as an OR of per-token substrings, so multi-word queries
|
|
17
|
+
# work (a single contiguous substring of the whole query is no longer
|
|
18
|
+
# required) while single-term/partial matches are preserved. An empty query
|
|
19
|
+
# (no tokens) matches everything, keeping prior "return all" behavior.
|
|
20
|
+
def matches?(text, query)
|
|
21
|
+
tokens = tokenize(query)
|
|
22
|
+
return true if tokens.empty?
|
|
23
|
+
haystack = text.to_s.downcase
|
|
24
|
+
tokens.any? { |t| haystack.include?(t) }
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -7,9 +7,10 @@ module Llmemory
|
|
|
7
7
|
# Persists embeddings in llmemory_embeddings (pgvector).
|
|
8
8
|
# Use when long_term_store is :active_record so hybrid search finds persisted embeddings.
|
|
9
9
|
class ActiveRecordStore < Base
|
|
10
|
-
def initialize(embedding_provider: nil)
|
|
10
|
+
def initialize(embedding_provider: nil, source_type: "edge")
|
|
11
11
|
self.class.load_model!
|
|
12
12
|
@embedding_provider = embedding_provider
|
|
13
|
+
@source_type = source_type.to_s
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
def self.load_model!
|
|
@@ -29,7 +30,7 @@ module Llmemory
|
|
|
29
30
|
text_content = (metadata || {}).dig("text") || (metadata || {}).dig(:text)
|
|
30
31
|
rec = Llmemory::VectorStore::ActiveRecordEmbedding.find_or_initialize_by(
|
|
31
32
|
user_id: user_id.to_s,
|
|
32
|
-
source_type:
|
|
33
|
+
source_type: @source_type,
|
|
33
34
|
source_id: id.to_s
|
|
34
35
|
)
|
|
35
36
|
rec.embedding = embedding.to_a.map(&:to_f)
|
|
@@ -46,7 +47,7 @@ module Llmemory
|
|
|
46
47
|
sanitized_vec = vec.map { |v| v.finite? ? v : 0.0 }
|
|
47
48
|
vector_literal = "[#{sanitized_vec.join(',')}]"
|
|
48
49
|
# pgvector cosine distance <=> (0 = same, 2 = opposite); score = 1 - distance for similarity
|
|
49
|
-
scope = Llmemory::VectorStore::ActiveRecordEmbedding.where(user_id: user_id.to_s)
|
|
50
|
+
scope = Llmemory::VectorStore::ActiveRecordEmbedding.where(user_id: user_id.to_s, source_type: @source_type)
|
|
50
51
|
rows = scope.select(
|
|
51
52
|
Llmemory::VectorStore::ActiveRecordEmbedding.arel_table[Arel.star],
|
|
52
53
|
Arel.sql("(embedding <=> '#{vector_literal}'::vector) AS distance")
|
|
@@ -54,14 +54,18 @@ module Llmemory
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def fetch_embedding(text)
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
result = nil
|
|
58
|
+
Llmemory::Instrumentation.instrument(:llm_embed, provider: :openai, model: @model, text_chars: text.to_s.length) do
|
|
59
|
+
response = connection.post("embeddings") do |req|
|
|
60
|
+
req.headers["Authorization"] = "Bearer #{@api_key}"
|
|
61
|
+
req.headers["Content-Type"] = "application/json"
|
|
62
|
+
req.body = { input: text.to_s.strip, model: @model }.to_json
|
|
63
|
+
end
|
|
64
|
+
raise Llmemory::LLMError, "OpenAI Embeddings API error: #{response.body}" unless response.success?
|
|
65
|
+
body = response.body.is_a?(Hash) ? response.body : JSON.parse(response.body.to_s)
|
|
66
|
+
result = body.dig("data", 0, "embedding")&.map(&:to_f) || Array.new(DEFAULT_DIMS, 0.0)
|
|
61
67
|
end
|
|
62
|
-
|
|
63
|
-
body = response.body.is_a?(Hash) ? response.body : JSON.parse(response.body.to_s)
|
|
64
|
-
body.dig("data", 0, "embedding")&.map(&:to_f) || Array.new(DEFAULT_DIMS, 0.0)
|
|
68
|
+
result
|
|
65
69
|
end
|
|
66
70
|
|
|
67
71
|
def connection
|
|
@@ -6,5 +6,19 @@ require_relative "vector_store/memory_store"
|
|
|
6
6
|
|
|
7
7
|
module Llmemory
|
|
8
8
|
module VectorStore
|
|
9
|
+
# Builds a vector store wired to OpenAI embeddings, selecting the backend
|
|
10
|
+
# from config (:active_record persists in llmemory_embeddings; otherwise
|
|
11
|
+
# in-process). `source_type` namespaces persisted embeddings so different
|
|
12
|
+
# memory types (edges, episodes, skills) never collide in the shared table.
|
|
13
|
+
def self.build(source_type: "edge")
|
|
14
|
+
embeddings = OpenAIEmbeddings.new
|
|
15
|
+
store_type = (Llmemory.configuration.long_term_store || :memory).to_s.to_sym
|
|
16
|
+
if store_type == :active_record || store_type == :activerecord
|
|
17
|
+
require_relative "vector_store/active_record_store"
|
|
18
|
+
ActiveRecordStore.new(embedding_provider: embeddings, source_type: source_type)
|
|
19
|
+
else
|
|
20
|
+
MemoryStore.new(embedding_provider: embeddings)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
9
23
|
end
|
|
10
24
|
end
|
data/lib/llmemory/version.rb
CHANGED
data/lib/llmemory.rb
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
require_relative "llmemory/version"
|
|
4
4
|
require_relative "llmemory/configuration"
|
|
5
5
|
require_relative "llmemory/provenance"
|
|
6
|
+
require_relative "llmemory/tokenizer"
|
|
7
|
+
require_relative "llmemory/instrumentation"
|
|
6
8
|
require_relative "llmemory/memory_module"
|
|
7
9
|
require_relative "llmemory/forget_log"
|
|
8
10
|
require_relative "llmemory/llm"
|
|
@@ -14,6 +16,7 @@ require_relative "llmemory/vector_store"
|
|
|
14
16
|
require_relative "llmemory/maintenance"
|
|
15
17
|
require_relative "llmemory/extractors"
|
|
16
18
|
require_relative "llmemory/reflection"
|
|
19
|
+
require_relative "llmemory/skill_mining"
|
|
17
20
|
require_relative "llmemory/actions"
|
|
18
21
|
require_relative "llmemory/memory"
|
|
19
22
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: llmemory
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- llmemory
|
|
@@ -106,21 +106,33 @@ files:
|
|
|
106
106
|
- LICENSE.txt
|
|
107
107
|
- README.md
|
|
108
108
|
- app/controllers/llmemory/dashboard/application_controller.rb
|
|
109
|
+
- app/controllers/llmemory/dashboard/episodic_controller.rb
|
|
110
|
+
- app/controllers/llmemory/dashboard/forget_log_controller.rb
|
|
109
111
|
- app/controllers/llmemory/dashboard/graph_controller.rb
|
|
110
112
|
- app/controllers/llmemory/dashboard/long_term_controller.rb
|
|
113
|
+
- app/controllers/llmemory/dashboard/maintenance_controller.rb
|
|
114
|
+
- app/controllers/llmemory/dashboard/procedural_controller.rb
|
|
115
|
+
- app/controllers/llmemory/dashboard/reflection_controller.rb
|
|
111
116
|
- app/controllers/llmemory/dashboard/search_controller.rb
|
|
112
117
|
- app/controllers/llmemory/dashboard/short_term_controller.rb
|
|
113
118
|
- app/controllers/llmemory/dashboard/stats_controller.rb
|
|
114
119
|
- app/controllers/llmemory/dashboard/users_controller.rb
|
|
120
|
+
- app/controllers/llmemory/dashboard/working_controller.rb
|
|
115
121
|
- app/views/layouts/application.html.erb
|
|
122
|
+
- app/views/llmemory/dashboard/episodic/index.html.erb
|
|
123
|
+
- app/views/llmemory/dashboard/forget_log/show.html.erb
|
|
116
124
|
- app/views/llmemory/dashboard/graph/index.html.erb
|
|
117
125
|
- app/views/llmemory/dashboard/long_term/categories.html.erb
|
|
118
126
|
- app/views/llmemory/dashboard/long_term/index.html.erb
|
|
127
|
+
- app/views/llmemory/dashboard/maintenance/show.html.erb
|
|
128
|
+
- app/views/llmemory/dashboard/procedural/index.html.erb
|
|
129
|
+
- app/views/llmemory/dashboard/reflection/show.html.erb
|
|
119
130
|
- app/views/llmemory/dashboard/search/index.html.erb
|
|
120
131
|
- app/views/llmemory/dashboard/short_term/show.html.erb
|
|
121
132
|
- app/views/llmemory/dashboard/stats/index.html.erb
|
|
122
133
|
- app/views/llmemory/dashboard/users/index.html.erb
|
|
123
134
|
- app/views/llmemory/dashboard/users/show.html.erb
|
|
135
|
+
- app/views/llmemory/dashboard/working/show.html.erb
|
|
124
136
|
- config/routes.rb
|
|
125
137
|
- exe/llmemory
|
|
126
138
|
- exe/llmemory-mcp
|
|
@@ -131,6 +143,8 @@ files:
|
|
|
131
143
|
- lib/llmemory/actions/reason.rb
|
|
132
144
|
- lib/llmemory/cli.rb
|
|
133
145
|
- lib/llmemory/cli/commands/base.rb
|
|
146
|
+
- lib/llmemory/cli/commands/episodic.rb
|
|
147
|
+
- lib/llmemory/cli/commands/forget_log.rb
|
|
134
148
|
- lib/llmemory/cli/commands/long_term.rb
|
|
135
149
|
- lib/llmemory/cli/commands/long_term/categories.rb
|
|
136
150
|
- lib/llmemory/cli/commands/long_term/edges.rb
|
|
@@ -138,11 +152,15 @@ files:
|
|
|
138
152
|
- lib/llmemory/cli/commands/long_term/graph.rb
|
|
139
153
|
- lib/llmemory/cli/commands/long_term/nodes.rb
|
|
140
154
|
- lib/llmemory/cli/commands/long_term/resources.rb
|
|
155
|
+
- lib/llmemory/cli/commands/maintain.rb
|
|
141
156
|
- lib/llmemory/cli/commands/mcp.rb
|
|
157
|
+
- lib/llmemory/cli/commands/mine_skills.rb
|
|
158
|
+
- lib/llmemory/cli/commands/procedural.rb
|
|
142
159
|
- lib/llmemory/cli/commands/search.rb
|
|
143
160
|
- lib/llmemory/cli/commands/short_term.rb
|
|
144
161
|
- lib/llmemory/cli/commands/stats.rb
|
|
145
162
|
- lib/llmemory/cli/commands/users.rb
|
|
163
|
+
- lib/llmemory/cli/commands/working.rb
|
|
146
164
|
- lib/llmemory/configuration.rb
|
|
147
165
|
- lib/llmemory/dashboard.rb
|
|
148
166
|
- lib/llmemory/dashboard/engine.rb
|
|
@@ -150,6 +168,7 @@ files:
|
|
|
150
168
|
- lib/llmemory/extractors/entity_relation_extractor.rb
|
|
151
169
|
- lib/llmemory/extractors/fact_extractor.rb
|
|
152
170
|
- lib/llmemory/forget_log.rb
|
|
171
|
+
- lib/llmemory/instrumentation.rb
|
|
153
172
|
- lib/llmemory/llm.rb
|
|
154
173
|
- lib/llmemory/llm/anthropic.rb
|
|
155
174
|
- lib/llmemory/llm/base.rb
|
|
@@ -159,7 +178,10 @@ files:
|
|
|
159
178
|
- lib/llmemory/long_term/episodic/episode.rb
|
|
160
179
|
- lib/llmemory/long_term/episodic/memory.rb
|
|
161
180
|
- lib/llmemory/long_term/episodic/storage.rb
|
|
181
|
+
- lib/llmemory/long_term/episodic/storages/active_record_models.rb
|
|
182
|
+
- lib/llmemory/long_term/episodic/storages/active_record_storage.rb
|
|
162
183
|
- lib/llmemory/long_term/episodic/storages/base.rb
|
|
184
|
+
- lib/llmemory/long_term/episodic/storages/database_storage.rb
|
|
163
185
|
- lib/llmemory/long_term/episodic/storages/file_storage.rb
|
|
164
186
|
- lib/llmemory/long_term/episodic/storages/memory_storage.rb
|
|
165
187
|
- lib/llmemory/long_term/file_based.rb
|
|
@@ -190,23 +212,36 @@ files:
|
|
|
190
212
|
- lib/llmemory/long_term/procedural/memory.rb
|
|
191
213
|
- lib/llmemory/long_term/procedural/skill.rb
|
|
192
214
|
- lib/llmemory/long_term/procedural/storage.rb
|
|
215
|
+
- lib/llmemory/long_term/procedural/storages/active_record_models.rb
|
|
216
|
+
- lib/llmemory/long_term/procedural/storages/active_record_storage.rb
|
|
193
217
|
- lib/llmemory/long_term/procedural/storages/base.rb
|
|
218
|
+
- lib/llmemory/long_term/procedural/storages/database_storage.rb
|
|
194
219
|
- lib/llmemory/long_term/procedural/storages/file_storage.rb
|
|
195
220
|
- lib/llmemory/long_term/procedural/storages/memory_storage.rb
|
|
196
221
|
- lib/llmemory/maintenance.rb
|
|
222
|
+
- lib/llmemory/maintenance/cognitive_pass.rb
|
|
197
223
|
- lib/llmemory/maintenance/consolidator.rb
|
|
198
224
|
- lib/llmemory/maintenance/reindexer.rb
|
|
199
225
|
- lib/llmemory/maintenance/runner.rb
|
|
200
226
|
- lib/llmemory/maintenance/summarizer.rb
|
|
227
|
+
- lib/llmemory/maintenance/ttl_expiry.rb
|
|
201
228
|
- lib/llmemory/mcp.rb
|
|
202
229
|
- lib/llmemory/mcp/authentication.rb
|
|
203
230
|
- lib/llmemory/mcp/server.rb
|
|
204
231
|
- lib/llmemory/mcp/tools/memory_add_message.rb
|
|
205
232
|
- lib/llmemory/mcp/tools/memory_consolidate.rb
|
|
233
|
+
- lib/llmemory/mcp/tools/memory_episode_record.rb
|
|
234
|
+
- lib/llmemory/mcp/tools/memory_episodes.rb
|
|
235
|
+
- lib/llmemory/mcp/tools/memory_forget.rb
|
|
206
236
|
- lib/llmemory/mcp/tools/memory_info.rb
|
|
237
|
+
- lib/llmemory/mcp/tools/memory_maintain.rb
|
|
238
|
+
- lib/llmemory/mcp/tools/memory_mine_skills.rb
|
|
207
239
|
- lib/llmemory/mcp/tools/memory_retrieve.rb
|
|
208
240
|
- lib/llmemory/mcp/tools/memory_save.rb
|
|
209
241
|
- lib/llmemory/mcp/tools/memory_search.rb
|
|
242
|
+
- lib/llmemory/mcp/tools/memory_skill_register.rb
|
|
243
|
+
- lib/llmemory/mcp/tools/memory_skill_report.rb
|
|
244
|
+
- lib/llmemory/mcp/tools/memory_skills.rb
|
|
210
245
|
- lib/llmemory/mcp/tools/memory_stats.rb
|
|
211
246
|
- lib/llmemory/mcp/tools/memory_timeline.rb
|
|
212
247
|
- lib/llmemory/mcp/tools/memory_timeline_context.rb
|
|
@@ -235,6 +270,9 @@ files:
|
|
|
235
270
|
- lib/llmemory/short_term/stores/memory_store.rb
|
|
236
271
|
- lib/llmemory/short_term/stores/postgres_store.rb
|
|
237
272
|
- lib/llmemory/short_term/stores/redis_store.rb
|
|
273
|
+
- lib/llmemory/skill_mining.rb
|
|
274
|
+
- lib/llmemory/skill_mining/miner.rb
|
|
275
|
+
- lib/llmemory/tokenizer.rb
|
|
238
276
|
- lib/llmemory/vector_store.rb
|
|
239
277
|
- lib/llmemory/vector_store/active_record_embedding.rb
|
|
240
278
|
- lib/llmemory/vector_store/active_record_store.rb
|