swarm_memory 2.2.2 → 2.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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6217058c4241029650e057e4f28c75eb1c6105f797657eb7c039eb307fe9bcab
|
|
4
|
+
data.tar.gz: a9f5d039fe4dd776dff184fce3a539bf40e3bfe9f150698b26847e2953bc5e46
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 883afdf0f09de8425226e1ef1138b9f657de2a92b9efbb2b2262315479c3bc2a83542151a73d484ee632d6e5e5921e1f2232d7361d6c55457d530d982569e681
|
|
7
|
+
data.tar.gz: 963e4ba618cde5bdeb496815044b9c791fb68c9fb28f7543fcba75d93f77d095638d05417338132143b57dc0c6b845b7fad4f8853b433b845545272c36aa2e37
|
|
@@ -181,6 +181,9 @@ module SwarmMemory
|
|
|
181
181
|
|
|
182
182
|
# Calculate hybrid scores combining semantic similarity and keyword matching
|
|
183
183
|
#
|
|
184
|
+
# When keyword_score is 0 (no tag matches), falls back to pure semantic scoring
|
|
185
|
+
# to avoid penalizing results that have excellent semantic matches but no tag overlap.
|
|
186
|
+
#
|
|
184
187
|
# @param results [Array<Hash>] Results with semantic :similarity scores
|
|
185
188
|
# @param query_keywords [Array<String>] Keywords from query
|
|
186
189
|
# @return [Array<Hash>] Results with updated :similarity (hybrid score) and debug info
|
|
@@ -189,8 +192,13 @@ module SwarmMemory
|
|
|
189
192
|
semantic_score = result[:similarity]
|
|
190
193
|
keyword_score = calculate_keyword_score(result, query_keywords)
|
|
191
194
|
|
|
192
|
-
#
|
|
193
|
-
|
|
195
|
+
# Fallback to pure semantic when no keyword matches
|
|
196
|
+
# This prevents penalizing results with excellent semantic matches but no tag overlap
|
|
197
|
+
hybrid_score = if keyword_score.zero?
|
|
198
|
+
semantic_score
|
|
199
|
+
else
|
|
200
|
+
(@semantic_weight * semantic_score) + (@keyword_weight * keyword_score)
|
|
201
|
+
end
|
|
194
202
|
|
|
195
203
|
# Update result with hybrid score and debug info
|
|
196
204
|
result.merge(
|
|
@@ -18,7 +18,9 @@ module SwarmMemory
|
|
|
18
18
|
#
|
|
19
19
|
# @param adapter [Adapters::Base] Storage adapter
|
|
20
20
|
# @param embedder [Embeddings::Embedder, nil] Optional embedder for semantic search
|
|
21
|
-
|
|
21
|
+
# @param semantic_weight [Float, nil] Weight for semantic similarity in hybrid search (0.0-1.0)
|
|
22
|
+
# @param keyword_weight [Float, nil] Weight for keyword matching in hybrid search (0.0-1.0)
|
|
23
|
+
def initialize(adapter:, embedder: nil, semantic_weight: nil, keyword_weight: nil)
|
|
22
24
|
raise ArgumentError, "adapter is required" unless adapter.is_a?(Adapters::Base)
|
|
23
25
|
|
|
24
26
|
@adapter = adapter
|
|
@@ -26,7 +28,10 @@ module SwarmMemory
|
|
|
26
28
|
|
|
27
29
|
# Create semantic index if embedder is provided
|
|
28
30
|
@semantic_index = if embedder
|
|
29
|
-
|
|
31
|
+
index_options = { adapter: adapter, embedder: embedder }
|
|
32
|
+
index_options[:semantic_weight] = semantic_weight if semantic_weight
|
|
33
|
+
index_options[:keyword_weight] = keyword_weight if keyword_weight
|
|
34
|
+
SemanticIndex.new(**index_options)
|
|
30
35
|
end
|
|
31
36
|
end
|
|
32
37
|
|
|
@@ -84,6 +84,43 @@ module SwarmMemory
|
|
|
84
84
|
@mode = value.to_sym
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
+
# DSL method to set/get semantic weight for hybrid search
|
|
88
|
+
#
|
|
89
|
+
# Controls how much semantic (embedding) similarity affects search results.
|
|
90
|
+
# Default is 0.5 (50%). Set to 1.0 for pure semantic search.
|
|
91
|
+
#
|
|
92
|
+
# @param value [Float, nil] Weight between 0.0 and 1.0
|
|
93
|
+
# @return [Float, nil] Current semantic weight
|
|
94
|
+
#
|
|
95
|
+
# @example Pure semantic search (no keyword penalty)
|
|
96
|
+
# semantic_weight 1.0
|
|
97
|
+
# keyword_weight 0.0
|
|
98
|
+
def semantic_weight(value = nil)
|
|
99
|
+
if value.nil?
|
|
100
|
+
@adapter_options[:semantic_weight]
|
|
101
|
+
else
|
|
102
|
+
@adapter_options[:semantic_weight] = value.to_f
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# DSL method to set/get keyword weight for hybrid search
|
|
107
|
+
#
|
|
108
|
+
# Controls how much keyword (tag) matching affects search results.
|
|
109
|
+
# Default is 0.5 (50%). Set to 0.0 to disable keyword matching.
|
|
110
|
+
#
|
|
111
|
+
# @param value [Float, nil] Weight between 0.0 and 1.0
|
|
112
|
+
# @return [Float, nil] Current keyword weight
|
|
113
|
+
#
|
|
114
|
+
# @example Disable keyword matching
|
|
115
|
+
# keyword_weight 0.0
|
|
116
|
+
def keyword_weight(value = nil)
|
|
117
|
+
if value.nil?
|
|
118
|
+
@adapter_options[:keyword_weight]
|
|
119
|
+
else
|
|
120
|
+
@adapter_options[:keyword_weight] = value.to_f
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
87
124
|
# Check if memory is enabled
|
|
88
125
|
#
|
|
89
126
|
# @return [Boolean] True if adapter is configured with required options
|
|
@@ -110,10 +110,12 @@ module SwarmMemory
|
|
|
110
110
|
# MemoryConfig object (from DSL)
|
|
111
111
|
[config.adapter_type, config.adapter_options]
|
|
112
112
|
elsif config.is_a?(Hash)
|
|
113
|
-
# Hash (from YAML)
|
|
113
|
+
# Hash (from YAML) - symbolize keys for adapter compatibility
|
|
114
114
|
adapter = (config[:adapter] || config["adapter"] || :filesystem).to_sym
|
|
115
|
-
options = config.reject { |k, _v|
|
|
116
|
-
|
|
115
|
+
options = config.reject { |k, _v| [:adapter, "adapter", :mode, "mode"].include?(k) }
|
|
116
|
+
# Symbolize keys so adapter receives keyword arguments correctly
|
|
117
|
+
symbolized_options = options.transform_keys { |k| k.to_s.to_sym }
|
|
118
|
+
[adapter, symbolized_options]
|
|
117
119
|
else
|
|
118
120
|
raise SwarmSDK::ConfigurationError, "Invalid memory configuration for #{agent_name}"
|
|
119
121
|
end
|
|
@@ -125,7 +127,17 @@ module SwarmMemory
|
|
|
125
127
|
raise SwarmSDK::ConfigurationError, "#{e.message} for agent #{agent_name}"
|
|
126
128
|
end
|
|
127
129
|
|
|
128
|
-
#
|
|
130
|
+
# Extract hybrid search weights and other SDK-level config (before passing to adapter)
|
|
131
|
+
# Keys are already symbolized at this point
|
|
132
|
+
semantic_weight = adapter_options.delete(:semantic_weight)
|
|
133
|
+
keyword_weight = adapter_options.delete(:keyword_weight)
|
|
134
|
+
|
|
135
|
+
# Remove other SDK-level threshold configs that shouldn't go to adapter
|
|
136
|
+
adapter_options.delete(:discovery_threshold)
|
|
137
|
+
adapter_options.delete(:discovery_threshold_short)
|
|
138
|
+
adapter_options.delete(:adaptive_word_cutoff)
|
|
139
|
+
|
|
140
|
+
# Instantiate adapter with options (weights removed, adapter doesn't need them)
|
|
129
141
|
# Note: Adapter is responsible for validating its own requirements
|
|
130
142
|
begin
|
|
131
143
|
adapter = adapter_class.new(**adapter_options)
|
|
@@ -137,8 +149,13 @@ module SwarmMemory
|
|
|
137
149
|
# Create embedder for semantic search
|
|
138
150
|
embedder = Embeddings::InformersEmbedder.new
|
|
139
151
|
|
|
140
|
-
# Create storage with embedder
|
|
141
|
-
Core::Storage.new(
|
|
152
|
+
# Create storage with embedder and hybrid search weights
|
|
153
|
+
Core::Storage.new(
|
|
154
|
+
adapter: adapter,
|
|
155
|
+
embedder: embedder,
|
|
156
|
+
semantic_weight: semantic_weight,
|
|
157
|
+
keyword_weight: keyword_weight,
|
|
158
|
+
)
|
|
142
159
|
end
|
|
143
160
|
|
|
144
161
|
# Parse memory configuration
|
data/lib/swarm_memory/version.rb
CHANGED