llmemory 0.1.13 → 0.1.15

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.
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "faraday"
4
4
  require "json"
5
+ require "digest"
5
6
  require_relative "base"
6
7
 
7
8
  module Llmemory
@@ -13,10 +14,46 @@ module Llmemory
13
14
  def initialize(api_key: nil, model: nil)
14
15
  @api_key = api_key || Llmemory.configuration.llm_api_key
15
16
  @model = model || DEFAULT_MODEL
17
+ @cache = {}
18
+ @cache_order = []
16
19
  end
17
20
 
18
21
  def embed(text)
19
22
  return Array.new(DEFAULT_DIMS, 0.0) if text.to_s.strip.empty?
23
+
24
+ if Llmemory.configuration.embedding_cache_enabled
25
+ key = cache_key(text)
26
+ return @cache[key].dup if @cache.key?(key)
27
+ end
28
+
29
+ result = fetch_embedding(text)
30
+
31
+ if Llmemory.configuration.embedding_cache_enabled
32
+ evict_if_needed
33
+ @cache[cache_key(text)] = result.dup
34
+ @cache_order << cache_key(text)
35
+ end
36
+
37
+ result
38
+ end
39
+
40
+ private
41
+
42
+ def cache_key(text)
43
+ Digest::SHA256.hexdigest("#{@model}:#{text.to_s.strip}")
44
+ end
45
+
46
+ def evict_if_needed
47
+ max = Llmemory.configuration.embedding_cache_max_entries.to_i
48
+ return if max <= 0 || @cache.size < max
49
+
50
+ while @cache_order.any? && @cache.size >= max
51
+ k = @cache_order.shift
52
+ @cache.delete(k)
53
+ end
54
+ end
55
+
56
+ def fetch_embedding(text)
20
57
  response = connection.post("embeddings") do |req|
21
58
  req.headers["Authorization"] = "Bearer #{@api_key}"
22
59
  req.headers["Content-Type"] = "application/json"
@@ -27,16 +64,6 @@ module Llmemory
27
64
  body.dig("data", 0, "embedding")&.map(&:to_f) || Array.new(DEFAULT_DIMS, 0.0)
28
65
  end
29
66
 
30
- def store(id:, embedding:, metadata: {})
31
- raise NotImplementedError, "OpenAIEmbeddings does not store; use a VectorStore backend (e.g. MemoryStore)"
32
- end
33
-
34
- def search(query_embedding, top_k: 10)
35
- raise NotImplementedError, "OpenAIEmbeddings does not search; use a VectorStore backend"
36
- end
37
-
38
- private
39
-
40
67
  def connection
41
68
  @connection ||= Faraday.new(url: "https://api.openai.com/v1") do |f|
42
69
  f.request :json
@@ -44,6 +71,14 @@ module Llmemory
44
71
  f.adapter Faraday.default_adapter
45
72
  end
46
73
  end
74
+
75
+ def store(id:, embedding:, metadata: {})
76
+ raise NotImplementedError, "OpenAIEmbeddings does not store; use a VectorStore backend (e.g. MemoryStore)"
77
+ end
78
+
79
+ def search(query_embedding, top_k: 10)
80
+ raise NotImplementedError, "OpenAIEmbeddings does not search; use a VectorStore backend"
81
+ end
47
82
  end
48
83
  end
49
84
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Llmemory
4
- VERSION = "0.1.13"
4
+ VERSION = "0.1.15"
5
5
  end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ namespace :release do
4
+ desc "Bump version (patch|minor|major). Checks: branch=main, no uncommitted changes, tests pass. Then: Gemfile.lock, CHANGELOG, commit, push, tag"
5
+ task :bump, [:bump_type] => [] do |_t, args|
6
+ require_relative "../llmemory/version"
7
+
8
+ # Pre-flight checks
9
+ current_branch = `git rev-parse --abbrev-ref HEAD`.strip
10
+ abort "Current branch must be main (got: #{current_branch})" unless current_branch == "main"
11
+
12
+ # Allow only release-related files to be modified (we'll commit them)
13
+ release_files = %w[lib/llmemory/version.rb Gemfile.lock CHANGELOG.txt]
14
+ status_lines = `git status --porcelain`.strip.lines
15
+ other_changes = status_lines.reject do |line|
16
+ path = line.sub(/\A..\s+/, "").strip
17
+ release_files.include?(path)
18
+ end
19
+ abort "Working tree has uncommitted changes outside release files. Commit or stash them first." unless other_changes.empty?
20
+
21
+ puts "Running tests..."
22
+ sh "bundle exec rspec"
23
+ puts "Tests passed.\n\n"
24
+
25
+ bump_type = (args[:bump_type] || "patch").to_s.downcase
26
+ unless %w[patch minor major].include?(bump_type)
27
+ abort "Bump type must be: patch, minor, or major"
28
+ end
29
+
30
+ seg = Gem::Version.new(Llmemory::VERSION).segments
31
+ new_version = case bump_type
32
+ when "patch" then Gem::Version.new("#{seg[0]}.#{seg[1] || 0}.#{(seg[2] || 0) + 1}")
33
+ when "minor" then Gem::Version.new("#{seg[0]}.#{(seg[1] || 0) + 1}.0")
34
+ when "major" then Gem::Version.new("#{(seg[0] || 0) + 1}.0.0")
35
+ end
36
+ new_version_s = new_version.to_s
37
+
38
+ puts "Bumping #{Llmemory::VERSION} -> #{new_version_s} (#{bump_type})"
39
+
40
+ # 1. Update version.rb
41
+ version_file = File.expand_path("../llmemory/version.rb", __dir__)
42
+ content = File.read(version_file)
43
+ content = content.sub(/VERSION = "[^"]+"/, %(VERSION = "#{new_version_s}"))
44
+ File.write(version_file, content)
45
+ puts " Updated lib/llmemory/version.rb"
46
+
47
+ # 2. bundle install
48
+ sh "bundle install"
49
+ puts " Updated Gemfile.lock"
50
+
51
+ # 3. Update CHANGELOG.txt
52
+ changelog_path = File.expand_path("../../CHANGELOG.txt", __dir__)
53
+ changelog_content = if File.exist?(changelog_path)
54
+ File.read(changelog_path)
55
+ else
56
+ ""
57
+ end
58
+
59
+ today = Time.now.strftime("%Y-%m-%d")
60
+ last_tag = `git describe --tags --abbrev=0 2>/dev/null`.strip
61
+ commits = if last_tag.empty?
62
+ `git log --oneline`.strip
63
+ else
64
+ `git log #{last_tag}..HEAD --oneline`.strip
65
+ end
66
+
67
+ new_entry = <<~CHANGELOG
68
+
69
+ ## [#{new_version_s}] - #{today}
70
+
71
+ ### Changes
72
+ #{commits.lines.map { |l| "- #{l.strip}" }.join("\n")}
73
+ CHANGELOG
74
+
75
+ header = "# Changelog\n\n"
76
+ if changelog_content.empty?
77
+ changelog_content = header + new_entry
78
+ else
79
+ changelog_content = header + changelog_content unless changelog_content.start_with?(header)
80
+ changelog_content = changelog_content.sub(/(# Changelog\n\n)/m, "\\1#{new_entry.lstrip}")
81
+ end
82
+ File.write(changelog_path, changelog_content)
83
+ puts " Updated CHANGELOG.txt"
84
+
85
+ # 4. Commit
86
+ sh "git add lib/llmemory/version.rb Gemfile.lock CHANGELOG.txt"
87
+ sh "git commit -m 'Release v#{new_version_s}'"
88
+
89
+ # 5. Push
90
+ sh "git push"
91
+
92
+ # 6. Tag
93
+ sh "git tag v#{new_version_s}"
94
+
95
+ # 7. Push tag
96
+ sh "git push origin v#{new_version_s}"
97
+
98
+ puts "\nDone. Released v#{new_version_s}"
99
+ end
100
+ end
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.1.13
4
+ version: 0.1.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - llmemory
@@ -37,6 +37,20 @@ dependencies:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
39
  version: '0.6'
40
+ - !ruby/object:Gem::Dependency
41
+ name: simplecov
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '0.22'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '0.22'
40
54
  - !ruby/object:Gem::Dependency
41
55
  name: rspec
42
56
  requirement: !ruby/object:Gem::Requirement
@@ -180,12 +194,18 @@ files:
180
194
  - lib/llmemory/mcp/tools/memory_timeline.rb
181
195
  - lib/llmemory/mcp/tools/memory_timeline_context.rb
182
196
  - lib/llmemory/memory.rb
197
+ - lib/llmemory/noise_filter.rb
183
198
  - lib/llmemory/retrieval.rb
199
+ - lib/llmemory/retrieval/bm25_scorer.rb
184
200
  - lib/llmemory/retrieval/context_assembler.rb
185
201
  - lib/llmemory/retrieval/engine.rb
202
+ - lib/llmemory/retrieval/mmr_reranker.rb
186
203
  - lib/llmemory/retrieval/temporal_ranker.rb
187
204
  - lib/llmemory/short_term.rb
188
205
  - lib/llmemory/short_term/checkpoint.rb
206
+ - lib/llmemory/short_term/message_sanitizer.rb
207
+ - lib/llmemory/short_term/pruner.rb
208
+ - lib/llmemory/short_term/session_lifecycle.rb
189
209
  - lib/llmemory/short_term/stores/active_record_checkpoint.rb
190
210
  - lib/llmemory/short_term/stores/active_record_store.rb
191
211
  - lib/llmemory/short_term/stores/base.rb
@@ -199,6 +219,7 @@ files:
199
219
  - lib/llmemory/vector_store/memory_store.rb
200
220
  - lib/llmemory/vector_store/openai_embeddings.rb
201
221
  - lib/llmemory/version.rb
222
+ - lib/tasks/release.rake
202
223
  homepage: https://github.com/entaina/llmemory
203
224
  licenses:
204
225
  - MIT