llmemory 0.2.1 → 0.2.3
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 +78 -1
- 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 +2 -0
- data/lib/llmemory/cli/commands/maintain.rb +62 -0
- data/lib/llmemory/cli/commands/mine_skills.rb +50 -0
- data/lib/llmemory/cli.rb +6 -0
- data/lib/llmemory/configuration.rb +28 -2
- data/lib/llmemory/crypto/cipher.rb +147 -0
- data/lib/llmemory/crypto/field_helpers.rb +110 -0
- data/lib/llmemory/instrumentation.rb +33 -0
- data/lib/llmemory/llm/anthropic.rb +21 -16
- data/lib/llmemory/llm/openai.rb +18 -13
- data/lib/llmemory/long_term/episodic/memory.rb +27 -13
- data/lib/llmemory/long_term/episodic/storage.rb +11 -4
- data/lib/llmemory/long_term/episodic/storages/active_record_storage.rb +33 -10
- data/lib/llmemory/long_term/episodic/storages/base.rb +15 -2
- data/lib/llmemory/long_term/episodic/storages/database_storage.rb +51 -8
- data/lib/llmemory/long_term/episodic/storages/file_storage.rb +47 -9
- data/lib/llmemory/long_term/episodic/storages/memory_storage.rb +35 -4
- data/lib/llmemory/long_term/file_based/memory.rb +12 -4
- data/lib/llmemory/long_term/file_based/storage.rb +11 -4
- data/lib/llmemory/long_term/file_based/storages/active_record_storage.rb +20 -12
- data/lib/llmemory/long_term/file_based/storages/base.rb +2 -2
- data/lib/llmemory/long_term/file_based/storages/database_storage.rb +28 -10
- data/lib/llmemory/long_term/file_based/storages/file_storage.rb +32 -16
- data/lib/llmemory/long_term/file_based/storages/memory_storage.rb +4 -2
- data/lib/llmemory/long_term/graph_based/memory.rb +16 -7
- data/lib/llmemory/long_term/graph_based/storage.rb +3 -2
- data/lib/llmemory/long_term/graph_based/storages/active_record_storage.rb +51 -23
- 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 +30 -16
- data/lib/llmemory/long_term/procedural/skill.rb +6 -2
- data/lib/llmemory/long_term/procedural/storage.rb +11 -4
- data/lib/llmemory/long_term/procedural/storages/active_record_storage.rb +47 -17
- data/lib/llmemory/long_term/procedural/storages/base.rb +14 -1
- data/lib/llmemory/long_term/procedural/storages/database_storage.rb +52 -10
- data/lib/llmemory/long_term/procedural/storages/file_storage.rb +49 -11
- data/lib/llmemory/long_term/procedural/storages/memory_storage.rb +36 -5
- 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 +5 -1
- data/lib/llmemory/mcp/tools/memory_maintain.rb +53 -0
- data/lib/llmemory/mcp/tools/memory_mine_skills.rb +53 -0
- data/lib/llmemory/memory.rb +60 -8
- data/lib/llmemory/memory_module.rb +13 -6
- data/lib/llmemory/reflection/reflector.rb +24 -20
- data/lib/llmemory/retrieval/engine.rb +25 -16
- data/lib/llmemory/short_term/checkpoint.rb +3 -2
- data/lib/llmemory/short_term/stores/active_record_store.rb +12 -10
- data/lib/llmemory/short_term/stores/memory_store.rb +1 -1
- data/lib/llmemory/short_term/stores/postgres_store.rb +11 -5
- data/lib/llmemory/short_term/stores/redis_store.rb +7 -5
- data/lib/llmemory/short_term/stores.rb +7 -6
- data/lib/llmemory/skill_mining/miner.rb +163 -0
- data/lib/llmemory/skill_mining.rb +8 -0
- data/lib/llmemory/vector_store/active_record_store.rb +24 -3
- data/lib/llmemory/vector_store/memory_store.rb +23 -3
- data/lib/llmemory/vector_store/openai_embeddings.rb +11 -7
- data/lib/llmemory/vector_store.rb +4 -3
- data/lib/llmemory/version.rb +1 -1
- data/lib/llmemory.rb +4 -0
- metadata +24 -1
|
@@ -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
|
|
@@ -7,10 +7,11 @@ 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, source_type: "edge")
|
|
10
|
+
def initialize(embedding_provider: nil, source_type: "edge", cipher: nil)
|
|
11
11
|
self.class.load_model!
|
|
12
12
|
@embedding_provider = embedding_provider
|
|
13
13
|
@source_type = source_type.to_s
|
|
14
|
+
@cipher = cipher || Llmemory.build_cipher
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def self.load_model!
|
|
@@ -34,7 +35,7 @@ module Llmemory
|
|
|
34
35
|
source_id: id.to_s
|
|
35
36
|
)
|
|
36
37
|
rec.embedding = embedding.to_a.map(&:to_f)
|
|
37
|
-
rec.text_content = text_content
|
|
38
|
+
rec.text_content = encrypt_text_content(text_content)
|
|
38
39
|
rec.save!
|
|
39
40
|
id
|
|
40
41
|
end
|
|
@@ -58,7 +59,11 @@ module Llmemory
|
|
|
58
59
|
{
|
|
59
60
|
id: r.source_id,
|
|
60
61
|
score: score,
|
|
61
|
-
metadata: {
|
|
62
|
+
metadata: {
|
|
63
|
+
"text" => decrypt_text_content(r.text_content),
|
|
64
|
+
"created_at" => r.created_at,
|
|
65
|
+
"user_id" => r.user_id
|
|
66
|
+
}
|
|
62
67
|
}
|
|
63
68
|
end
|
|
64
69
|
end
|
|
@@ -69,6 +74,22 @@ module Llmemory
|
|
|
69
74
|
query_embedding = @embedding_provider.embed(query_text)
|
|
70
75
|
search(query_embedding, top_k: top_k, user_id: user_id)
|
|
71
76
|
end
|
|
77
|
+
|
|
78
|
+
private
|
|
79
|
+
|
|
80
|
+
def encrypt_text_content(text)
|
|
81
|
+
return text if text.nil? || text.to_s.empty?
|
|
82
|
+
return text unless @cipher.enabled?
|
|
83
|
+
|
|
84
|
+
@cipher.encrypt(text.to_s)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def decrypt_text_content(text)
|
|
88
|
+
return text if text.nil?
|
|
89
|
+
return text unless text.is_a?(String) && @cipher.enabled? && @cipher.encrypted?(text)
|
|
90
|
+
|
|
91
|
+
@cipher.decrypt(text)
|
|
92
|
+
end
|
|
72
93
|
end
|
|
73
94
|
end
|
|
74
95
|
end
|
|
@@ -5,9 +5,10 @@ require_relative "base"
|
|
|
5
5
|
module Llmemory
|
|
6
6
|
module VectorStore
|
|
7
7
|
class MemoryStore < Base
|
|
8
|
-
def initialize(embedding_provider: nil)
|
|
8
|
+
def initialize(embedding_provider: nil, cipher: nil)
|
|
9
9
|
@entries = {}
|
|
10
10
|
@embedding_provider = embedding_provider
|
|
11
|
+
@cipher = cipher || Llmemory.build_cipher
|
|
11
12
|
end
|
|
12
13
|
|
|
13
14
|
def embed(text)
|
|
@@ -17,7 +18,13 @@ module Llmemory
|
|
|
17
18
|
|
|
18
19
|
def store(id:, embedding:, metadata: {}, user_id: nil)
|
|
19
20
|
key = user_id ? "#{user_id}:#{id}" : id.to_s
|
|
20
|
-
|
|
21
|
+
meta = (metadata || {}).dup
|
|
22
|
+
if meta["text"] && @cipher.enabled?
|
|
23
|
+
meta["text"] = @cipher.encrypt(meta["text"].to_s)
|
|
24
|
+
elsif meta[:text] && @cipher.enabled?
|
|
25
|
+
meta[:text] = @cipher.encrypt(meta[:text].to_s)
|
|
26
|
+
end
|
|
27
|
+
@entries[key] = { embedding: embedding.to_a.map(&:to_f), metadata: meta.merge("user_id" => user_id) }
|
|
21
28
|
id
|
|
22
29
|
end
|
|
23
30
|
|
|
@@ -27,7 +34,7 @@ module Llmemory
|
|
|
27
34
|
entries = user_id ? @entries.select { |k, _| k.to_s.start_with?("#{user_id}:") } : @entries
|
|
28
35
|
scores = entries.map do |id, data|
|
|
29
36
|
sim = cosine_similarity(query, data[:embedding])
|
|
30
|
-
{ id: id, score: sim, metadata: data[:metadata] }
|
|
37
|
+
{ id: id, score: sim, metadata: decrypt_metadata(data[:metadata]) }
|
|
31
38
|
end
|
|
32
39
|
scores.sort_by { |s| -s[:score] }.first(top_k)
|
|
33
40
|
end
|
|
@@ -40,6 +47,19 @@ module Llmemory
|
|
|
40
47
|
|
|
41
48
|
private
|
|
42
49
|
|
|
50
|
+
def decrypt_metadata(meta)
|
|
51
|
+
return meta unless meta.is_a?(Hash) && @cipher.enabled?
|
|
52
|
+
|
|
53
|
+
out = meta.dup
|
|
54
|
+
text = out["text"] || out[:text]
|
|
55
|
+
if text.is_a?(String) && @cipher.encrypted?(text)
|
|
56
|
+
decrypted = @cipher.decrypt(text)
|
|
57
|
+
out["text"] = decrypted
|
|
58
|
+
out[:text] = decrypted
|
|
59
|
+
end
|
|
60
|
+
out
|
|
61
|
+
end
|
|
62
|
+
|
|
43
63
|
def cosine_similarity(a, b)
|
|
44
64
|
return 0.0 if a.size != b.size || a.empty?
|
|
45
65
|
dot = a.zip(b).sum { |x, y| x * y }
|
|
@@ -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
|
|
@@ -10,14 +10,15 @@ module Llmemory
|
|
|
10
10
|
# from config (:active_record persists in llmemory_embeddings; otherwise
|
|
11
11
|
# in-process). `source_type` namespaces persisted embeddings so different
|
|
12
12
|
# memory types (edges, episodes, skills) never collide in the shared table.
|
|
13
|
-
def self.build(source_type: "edge")
|
|
13
|
+
def self.build(source_type: "edge", cipher: nil)
|
|
14
|
+
resolved_cipher = cipher || Llmemory.build_cipher
|
|
14
15
|
embeddings = OpenAIEmbeddings.new
|
|
15
16
|
store_type = (Llmemory.configuration.long_term_store || :memory).to_s.to_sym
|
|
16
17
|
if store_type == :active_record || store_type == :activerecord
|
|
17
18
|
require_relative "vector_store/active_record_store"
|
|
18
|
-
ActiveRecordStore.new(embedding_provider: embeddings, source_type: source_type)
|
|
19
|
+
ActiveRecordStore.new(embedding_provider: embeddings, source_type: source_type, cipher: resolved_cipher)
|
|
19
20
|
else
|
|
20
|
-
MemoryStore.new(embedding_provider: embeddings)
|
|
21
|
+
MemoryStore.new(embedding_provider: embeddings, cipher: resolved_cipher)
|
|
21
22
|
end
|
|
22
23
|
end
|
|
23
24
|
end
|
data/lib/llmemory/version.rb
CHANGED
data/lib/llmemory.rb
CHANGED
|
@@ -4,6 +4,7 @@ require_relative "llmemory/version"
|
|
|
4
4
|
require_relative "llmemory/configuration"
|
|
5
5
|
require_relative "llmemory/provenance"
|
|
6
6
|
require_relative "llmemory/tokenizer"
|
|
7
|
+
require_relative "llmemory/instrumentation"
|
|
7
8
|
require_relative "llmemory/memory_module"
|
|
8
9
|
require_relative "llmemory/forget_log"
|
|
9
10
|
require_relative "llmemory/llm"
|
|
@@ -15,6 +16,7 @@ require_relative "llmemory/vector_store"
|
|
|
15
16
|
require_relative "llmemory/maintenance"
|
|
16
17
|
require_relative "llmemory/extractors"
|
|
17
18
|
require_relative "llmemory/reflection"
|
|
19
|
+
require_relative "llmemory/skill_mining"
|
|
18
20
|
require_relative "llmemory/actions"
|
|
19
21
|
require_relative "llmemory/memory"
|
|
20
22
|
|
|
@@ -24,3 +26,5 @@ module Llmemory
|
|
|
24
26
|
class StoreError < Error; end
|
|
25
27
|
class LLMError < Error; end
|
|
26
28
|
end
|
|
29
|
+
|
|
30
|
+
require_relative "llmemory/crypto/cipher"
|
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.3
|
|
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
|
|
@@ -140,7 +152,9 @@ files:
|
|
|
140
152
|
- lib/llmemory/cli/commands/long_term/graph.rb
|
|
141
153
|
- lib/llmemory/cli/commands/long_term/nodes.rb
|
|
142
154
|
- lib/llmemory/cli/commands/long_term/resources.rb
|
|
155
|
+
- lib/llmemory/cli/commands/maintain.rb
|
|
143
156
|
- lib/llmemory/cli/commands/mcp.rb
|
|
157
|
+
- lib/llmemory/cli/commands/mine_skills.rb
|
|
144
158
|
- lib/llmemory/cli/commands/procedural.rb
|
|
145
159
|
- lib/llmemory/cli/commands/search.rb
|
|
146
160
|
- lib/llmemory/cli/commands/short_term.rb
|
|
@@ -148,12 +162,15 @@ files:
|
|
|
148
162
|
- lib/llmemory/cli/commands/users.rb
|
|
149
163
|
- lib/llmemory/cli/commands/working.rb
|
|
150
164
|
- lib/llmemory/configuration.rb
|
|
165
|
+
- lib/llmemory/crypto/cipher.rb
|
|
166
|
+
- lib/llmemory/crypto/field_helpers.rb
|
|
151
167
|
- lib/llmemory/dashboard.rb
|
|
152
168
|
- lib/llmemory/dashboard/engine.rb
|
|
153
169
|
- lib/llmemory/extractors.rb
|
|
154
170
|
- lib/llmemory/extractors/entity_relation_extractor.rb
|
|
155
171
|
- lib/llmemory/extractors/fact_extractor.rb
|
|
156
172
|
- lib/llmemory/forget_log.rb
|
|
173
|
+
- lib/llmemory/instrumentation.rb
|
|
157
174
|
- lib/llmemory/llm.rb
|
|
158
175
|
- lib/llmemory/llm/anthropic.rb
|
|
159
176
|
- lib/llmemory/llm/base.rb
|
|
@@ -204,10 +221,12 @@ files:
|
|
|
204
221
|
- lib/llmemory/long_term/procedural/storages/file_storage.rb
|
|
205
222
|
- lib/llmemory/long_term/procedural/storages/memory_storage.rb
|
|
206
223
|
- lib/llmemory/maintenance.rb
|
|
224
|
+
- lib/llmemory/maintenance/cognitive_pass.rb
|
|
207
225
|
- lib/llmemory/maintenance/consolidator.rb
|
|
208
226
|
- lib/llmemory/maintenance/reindexer.rb
|
|
209
227
|
- lib/llmemory/maintenance/runner.rb
|
|
210
228
|
- lib/llmemory/maintenance/summarizer.rb
|
|
229
|
+
- lib/llmemory/maintenance/ttl_expiry.rb
|
|
211
230
|
- lib/llmemory/mcp.rb
|
|
212
231
|
- lib/llmemory/mcp/authentication.rb
|
|
213
232
|
- lib/llmemory/mcp/server.rb
|
|
@@ -217,6 +236,8 @@ files:
|
|
|
217
236
|
- lib/llmemory/mcp/tools/memory_episodes.rb
|
|
218
237
|
- lib/llmemory/mcp/tools/memory_forget.rb
|
|
219
238
|
- lib/llmemory/mcp/tools/memory_info.rb
|
|
239
|
+
- lib/llmemory/mcp/tools/memory_maintain.rb
|
|
240
|
+
- lib/llmemory/mcp/tools/memory_mine_skills.rb
|
|
220
241
|
- lib/llmemory/mcp/tools/memory_retrieve.rb
|
|
221
242
|
- lib/llmemory/mcp/tools/memory_save.rb
|
|
222
243
|
- lib/llmemory/mcp/tools/memory_search.rb
|
|
@@ -251,6 +272,8 @@ files:
|
|
|
251
272
|
- lib/llmemory/short_term/stores/memory_store.rb
|
|
252
273
|
- lib/llmemory/short_term/stores/postgres_store.rb
|
|
253
274
|
- lib/llmemory/short_term/stores/redis_store.rb
|
|
275
|
+
- lib/llmemory/skill_mining.rb
|
|
276
|
+
- lib/llmemory/skill_mining/miner.rb
|
|
254
277
|
- lib/llmemory/tokenizer.rb
|
|
255
278
|
- lib/llmemory/vector_store.rb
|
|
256
279
|
- lib/llmemory/vector_store/active_record_embedding.rb
|