llmemory 0.2.2 → 0.2.4
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 +65 -1
- data/lib/llmemory/cli/commands/stats.rb +5 -0
- data/lib/llmemory/configuration.rb +22 -2
- data/lib/llmemory/crypto/cipher.rb +147 -0
- data/lib/llmemory/crypto/field_helpers.rb +110 -0
- data/lib/llmemory/instrumentation.rb +4 -2
- data/lib/llmemory/llm/anthropic.rb +10 -4
- data/lib/llmemory/llm/base.rb +42 -0
- data/lib/llmemory/llm/openai.rb +29 -13
- data/lib/llmemory/llm/response.rb +18 -0
- data/lib/llmemory/llm/tracking_client.rb +61 -0
- data/lib/llmemory/llm/usage.rb +31 -0
- data/lib/llmemory/llm/usage_ledger.rb +118 -0
- data/lib/llmemory/llm/usage_recorder.rb +37 -0
- data/lib/llmemory/llm.rb +5 -0
- data/lib/llmemory/long_term/episodic/memory.rb +16 -4
- data/lib/llmemory/long_term/episodic/storage.rb +11 -4
- data/lib/llmemory/long_term/episodic/storages/active_record_storage.rb +19 -6
- data/lib/llmemory/long_term/episodic/storages/database_storage.rb +25 -3
- data/lib/llmemory/long_term/episodic/storages/file_storage.rb +22 -5
- data/lib/llmemory/long_term/file_based/storage.rb +11 -4
- data/lib/llmemory/long_term/file_based/storages/active_record_storage.rb +16 -10
- data/lib/llmemory/long_term/file_based/storages/database_storage.rb +24 -8
- data/lib/llmemory/long_term/file_based/storages/file_storage.rb +28 -14
- data/lib/llmemory/long_term/graph_based/memory.rb +17 -3
- data/lib/llmemory/long_term/graph_based/storage.rb +3 -2
- data/lib/llmemory/long_term/graph_based/storages/active_record_storage.rb +47 -21
- data/lib/llmemory/long_term/procedural/memory.rb +16 -4
- data/lib/llmemory/long_term/procedural/storage.rb +11 -4
- data/lib/llmemory/long_term/procedural/storages/active_record_storage.rb +33 -13
- data/lib/llmemory/long_term/procedural/storages/database_storage.rb +25 -4
- data/lib/llmemory/long_term/procedural/storages/file_storage.rb +23 -6
- data/lib/llmemory/mcp/tools/memory_stats.rb +13 -0
- data/lib/llmemory/memory.rb +66 -15
- data/lib/llmemory/short_term/checkpoint.rb +5 -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/vector_store/active_record_store.rb +30 -3
- data/lib/llmemory/vector_store/memory_store.rb +29 -3
- data/lib/llmemory/vector_store/openai_embeddings.rb +23 -2
- data/lib/llmemory/vector_store.rb +4 -3
- data/lib/llmemory/version.rb +1 -1
- data/lib/llmemory.rb +2 -0
- metadata +8 -1
|
@@ -4,6 +4,7 @@ require "faraday"
|
|
|
4
4
|
require "json"
|
|
5
5
|
require "digest"
|
|
6
6
|
require_relative "base"
|
|
7
|
+
require_relative "../llm/usage"
|
|
7
8
|
|
|
8
9
|
module Llmemory
|
|
9
10
|
module VectorStore
|
|
@@ -11,11 +12,14 @@ module Llmemory
|
|
|
11
12
|
DEFAULT_MODEL = "text-embedding-3-small"
|
|
12
13
|
DEFAULT_DIMS = 1536
|
|
13
14
|
|
|
15
|
+
attr_reader :last_usage
|
|
16
|
+
|
|
14
17
|
def initialize(api_key: nil, model: nil)
|
|
15
18
|
@api_key = api_key || Llmemory.configuration.llm_api_key
|
|
16
19
|
@model = model || DEFAULT_MODEL
|
|
17
20
|
@cache = {}
|
|
18
21
|
@cache_order = []
|
|
22
|
+
@last_usage = Llmemory::LLM::Usage.zero
|
|
19
23
|
end
|
|
20
24
|
|
|
21
25
|
def embed(text)
|
|
@@ -23,7 +27,10 @@ module Llmemory
|
|
|
23
27
|
|
|
24
28
|
if Llmemory.configuration.embedding_cache_enabled
|
|
25
29
|
key = cache_key(text)
|
|
26
|
-
|
|
30
|
+
if @cache.key?(key)
|
|
31
|
+
@last_usage = Llmemory::LLM::Usage.zero
|
|
32
|
+
return @cache[key].dup
|
|
33
|
+
end
|
|
27
34
|
end
|
|
28
35
|
|
|
29
36
|
result = fetch_embedding(text)
|
|
@@ -55,7 +62,8 @@ module Llmemory
|
|
|
55
62
|
|
|
56
63
|
def fetch_embedding(text)
|
|
57
64
|
result = nil
|
|
58
|
-
|
|
65
|
+
payload = { provider: :openai, model: @model, text_chars: text.to_s.length }
|
|
66
|
+
Llmemory::Instrumentation.instrument(:llm_embed, payload) do
|
|
59
67
|
response = connection.post("embeddings") do |req|
|
|
60
68
|
req.headers["Authorization"] = "Bearer #{@api_key}"
|
|
61
69
|
req.headers["Content-Type"] = "application/json"
|
|
@@ -63,11 +71,24 @@ module Llmemory
|
|
|
63
71
|
end
|
|
64
72
|
raise Llmemory::LLMError, "OpenAI Embeddings API error: #{response.body}" unless response.success?
|
|
65
73
|
body = response.body.is_a?(Hash) ? response.body : JSON.parse(response.body.to_s)
|
|
74
|
+
@last_usage = parse_embed_usage(body["usage"])
|
|
75
|
+
payload.merge!(
|
|
76
|
+
input_tokens: @last_usage.input_tokens,
|
|
77
|
+
output_tokens: @last_usage.output_tokens,
|
|
78
|
+
total_tokens: @last_usage.total_tokens
|
|
79
|
+
)
|
|
66
80
|
result = body.dig("data", 0, "embedding")&.map(&:to_f) || Array.new(DEFAULT_DIMS, 0.0)
|
|
67
81
|
end
|
|
68
82
|
result
|
|
69
83
|
end
|
|
70
84
|
|
|
85
|
+
def parse_embed_usage(raw)
|
|
86
|
+
return Llmemory::LLM::Usage.zero unless raw.is_a?(Hash)
|
|
87
|
+
|
|
88
|
+
total = raw["total_tokens"] || raw[:total_tokens] || 0
|
|
89
|
+
Llmemory::LLM::Usage.new(input_tokens: 0, output_tokens: 0, total_tokens: total)
|
|
90
|
+
end
|
|
91
|
+
|
|
71
92
|
def connection
|
|
72
93
|
@connection ||= Faraday.new(url: "https://api.openai.com/v1") do |f|
|
|
73
94
|
f.request :json
|
|
@@ -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
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.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- llmemory
|
|
@@ -162,6 +162,8 @@ files:
|
|
|
162
162
|
- lib/llmemory/cli/commands/users.rb
|
|
163
163
|
- lib/llmemory/cli/commands/working.rb
|
|
164
164
|
- lib/llmemory/configuration.rb
|
|
165
|
+
- lib/llmemory/crypto/cipher.rb
|
|
166
|
+
- lib/llmemory/crypto/field_helpers.rb
|
|
165
167
|
- lib/llmemory/dashboard.rb
|
|
166
168
|
- lib/llmemory/dashboard/engine.rb
|
|
167
169
|
- lib/llmemory/extractors.rb
|
|
@@ -173,6 +175,11 @@ files:
|
|
|
173
175
|
- lib/llmemory/llm/anthropic.rb
|
|
174
176
|
- lib/llmemory/llm/base.rb
|
|
175
177
|
- lib/llmemory/llm/openai.rb
|
|
178
|
+
- lib/llmemory/llm/response.rb
|
|
179
|
+
- lib/llmemory/llm/tracking_client.rb
|
|
180
|
+
- lib/llmemory/llm/usage.rb
|
|
181
|
+
- lib/llmemory/llm/usage_ledger.rb
|
|
182
|
+
- lib/llmemory/llm/usage_recorder.rb
|
|
176
183
|
- lib/llmemory/long_term.rb
|
|
177
184
|
- lib/llmemory/long_term/episodic.rb
|
|
178
185
|
- lib/llmemory/long_term/episodic/episode.rb
|