htm 0.0.18 → 0.0.30
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/CHANGELOG.md +119 -1
- data/README.md +12 -0
- data/Rakefile +104 -18
- data/db/migrate/00001_enable_extensions.rb +9 -5
- data/db/migrate/00002_create_robots.rb +18 -6
- data/db/migrate/00003_create_file_sources.rb +30 -17
- data/db/migrate/00004_create_nodes.rb +60 -48
- data/db/migrate/00005_create_tags.rb +24 -12
- data/db/migrate/00006_create_node_tags.rb +28 -13
- data/db/migrate/00007_create_robot_nodes.rb +40 -26
- data/db/schema.sql +17 -1
- data/db/seeds.rb +34 -34
- data/docs/api/embedding-service.md +140 -110
- data/docs/api/yard/HTM/ActiveRecordConfig.md +6 -0
- data/docs/api/yard/HTM/Config.md +173 -0
- data/docs/api/yard/HTM/ConfigSection.md +28 -0
- data/docs/api/yard/HTM/Database.md +1 -1
- data/docs/api/yard/HTM/Railtie.md +2 -2
- data/docs/api/yard/HTM.md +0 -57
- data/docs/api/yard/index.csv +76 -61
- data/docs/api/yard-reference.md +2 -1
- data/docs/architecture/adrs/003-ollama-embeddings.md +45 -36
- data/docs/architecture/adrs/004-hive-mind.md +1 -1
- data/docs/architecture/adrs/008-robot-identification.md +1 -1
- data/docs/architecture/index.md +11 -9
- data/docs/architecture/overview.md +11 -7
- data/docs/assets/images/balanced-strategy-decay.svg +41 -0
- data/docs/assets/images/class-hierarchy.svg +1 -1
- data/docs/assets/images/eviction-priority.svg +43 -0
- data/docs/assets/images/exception-hierarchy.svg +2 -2
- data/docs/assets/images/hive-mind-shared-memory.svg +52 -0
- data/docs/assets/images/htm-architecture-overview.svg +3 -3
- data/docs/assets/images/htm-core-components.svg +4 -4
- data/docs/assets/images/htm-layered-architecture.svg +1 -1
- data/docs/assets/images/htm-memory-addition-flow.svg +2 -2
- data/docs/assets/images/htm-memory-recall-flow.svg +2 -2
- data/docs/assets/images/memory-topology.svg +53 -0
- data/docs/assets/images/two-tier-memory-architecture.svg +55 -0
- data/docs/database/naming-convention.md +244 -0
- data/docs/database_rake_tasks.md +31 -0
- data/docs/development/rake-tasks.md +80 -35
- data/docs/development/setup.md +76 -44
- data/docs/examples/basic-usage.md +133 -0
- data/docs/examples/config-files.md +170 -0
- data/docs/examples/file-loading.md +208 -0
- data/docs/examples/index.md +116 -0
- data/docs/examples/llm-configuration.md +168 -0
- data/docs/examples/mcp-client.md +172 -0
- data/docs/examples/rails-integration.md +173 -0
- data/docs/examples/robot-groups.md +210 -0
- data/docs/examples/sinatra-integration.md +218 -0
- data/docs/examples/standalone-app.md +216 -0
- data/docs/examples/telemetry.md +224 -0
- data/docs/examples/timeframes.md +143 -0
- data/docs/getting-started/installation.md +97 -40
- data/docs/getting-started/quick-start.md +28 -11
- data/docs/guides/configuration.md +515 -0
- data/docs/guides/file-loading.md +322 -0
- data/docs/guides/getting-started.md +40 -9
- data/docs/guides/index.md +3 -3
- data/docs/guides/mcp-server.md +100 -13
- data/docs/guides/propositions.md +264 -0
- data/docs/guides/recalling-memories.md +4 -4
- data/docs/guides/search-strategies.md +3 -3
- data/docs/guides/tags.md +318 -0
- data/docs/guides/telemetry.md +229 -0
- data/docs/index.md +8 -16
- data/docs/{architecture → robots}/hive-mind.md +8 -111
- data/docs/robots/index.md +73 -0
- data/docs/{guides → robots}/multi-robot.md +3 -3
- data/docs/{guides → robots}/robot-groups.md +8 -7
- data/docs/{architecture → robots}/two-tier-memory.md +13 -149
- data/docs/robots/why-robots.md +85 -0
- data/examples/.envrc +6 -0
- data/examples/.gitignore +2 -0
- data/examples/00_create_examples_db.rb +94 -0
- data/examples/{basic_usage.rb → 01_basic_usage.rb} +12 -16
- data/examples/{custom_llm_configuration.rb → 03_custom_llm_configuration.rb} +13 -3
- data/examples/{file_loader_usage.rb → 04_file_loader_usage.rb} +11 -14
- data/examples/{timeframe_demo.rb → 05_timeframe_demo.rb} +10 -3
- data/examples/{example_app → 06_example_app}/app.rb +15 -15
- data/examples/{cli_app → 07_cli_app}/htm_cli.rb +15 -22
- data/examples/08_sinatra_app/Gemfile.lock +241 -0
- data/examples/{sinatra_app → 08_sinatra_app}/app.rb +19 -18
- data/examples/{mcp_client.rb → 09_mcp_client.rb} +5 -8
- data/examples/{telemetry → 10_telemetry}/SETUP_README.md +1 -1
- data/examples/{telemetry → 10_telemetry}/demo.rb +14 -10
- data/examples/11_robot_groups/README.md +335 -0
- data/examples/{robot_groups → 11_robot_groups/lib}/robot_worker.rb +17 -3
- data/examples/{robot_groups → 11_robot_groups}/multi_process.rb +9 -9
- data/examples/{robot_groups → 11_robot_groups}/same_process.rb +9 -12
- data/examples/{rails_app → 12_rails_app}/Gemfile +3 -0
- data/examples/{rails_app → 12_rails_app}/Gemfile.lock +87 -58
- data/examples/{rails_app → 12_rails_app}/app/controllers/dashboard_controller.rb +10 -6
- data/examples/{rails_app → 12_rails_app}/app/controllers/files_controller.rb +5 -5
- data/examples/{rails_app → 12_rails_app}/app/controllers/memories_controller.rb +11 -7
- data/examples/{rails_app → 12_rails_app}/app/controllers/robots_controller.rb +8 -8
- data/examples/12_rails_app/app/controllers/tags_controller.rb +36 -0
- data/examples/{rails_app → 12_rails_app}/app/views/dashboard/index.html.erb +2 -2
- data/examples/{rails_app → 12_rails_app}/app/views/files/new.html.erb +5 -2
- data/examples/{rails_app → 12_rails_app}/app/views/memories/_memory_card.html.erb +3 -3
- data/examples/{rails_app → 12_rails_app}/app/views/memories/deleted.html.erb +3 -3
- data/examples/{rails_app → 12_rails_app}/app/views/memories/edit.html.erb +3 -3
- data/examples/{rails_app → 12_rails_app}/app/views/memories/show.html.erb +4 -4
- data/examples/{rails_app → 12_rails_app}/app/views/robots/index.html.erb +2 -2
- data/examples/{rails_app → 12_rails_app}/app/views/robots/show.html.erb +4 -4
- data/examples/{rails_app → 12_rails_app}/app/views/search/index.html.erb +1 -1
- data/examples/{rails_app → 12_rails_app}/app/views/tags/index.html.erb +2 -2
- data/examples/{rails_app → 12_rails_app}/app/views/tags/show.html.erb +1 -1
- data/examples/12_rails_app/config/initializers/htm.rb +7 -0
- data/examples/12_rails_app/config/initializers/rack.rb +5 -0
- data/examples/README.md +230 -211
- data/examples/examples_helper.rb +138 -0
- data/lib/htm/config/builder.rb +167 -0
- data/lib/htm/config/database.rb +317 -0
- data/lib/htm/config/defaults.yml +41 -13
- data/lib/htm/config/section.rb +74 -0
- data/lib/htm/config/validator.rb +83 -0
- data/lib/htm/config.rb +65 -361
- data/lib/htm/database.rb +85 -127
- data/lib/htm/errors.rb +14 -0
- data/lib/htm/integrations/sinatra.rb +13 -44
- data/lib/htm/job_adapter.rb +75 -1
- data/lib/htm/jobs/generate_embedding_job.rb +3 -4
- data/lib/htm/jobs/generate_propositions_job.rb +4 -5
- data/lib/htm/jobs/generate_tags_job.rb +16 -15
- data/lib/htm/loaders/defaults_loader.rb +23 -0
- data/lib/htm/loaders/markdown_loader.rb +17 -15
- data/lib/htm/loaders/xdg_config_loader.rb +9 -9
- data/lib/htm/long_term_memory/fulltext_search.rb +14 -14
- data/lib/htm/long_term_memory/hybrid_search.rb +396 -229
- data/lib/htm/long_term_memory/node_operations.rb +24 -23
- data/lib/htm/long_term_memory/relevance_scorer.rb +23 -20
- data/lib/htm/long_term_memory/robot_operations.rb +4 -4
- data/lib/htm/long_term_memory/tag_operations.rb +91 -77
- data/lib/htm/long_term_memory/vector_search.rb +4 -5
- data/lib/htm/long_term_memory.rb +13 -13
- data/lib/htm/mcp/cli.rb +115 -8
- data/lib/htm/mcp/resources.rb +4 -3
- data/lib/htm/mcp/server.rb +5 -4
- data/lib/htm/mcp/tools.rb +37 -28
- data/lib/htm/migration.rb +72 -0
- data/lib/htm/models/file_source.rb +52 -31
- data/lib/htm/models/node.rb +224 -108
- data/lib/htm/models/node_tag.rb +49 -28
- data/lib/htm/models/robot.rb +38 -27
- data/lib/htm/models/robot_node.rb +63 -35
- data/lib/htm/models/tag.rb +126 -123
- data/lib/htm/observability.rb +45 -41
- data/lib/htm/proposition_service.rb +76 -7
- data/lib/htm/railtie.rb +2 -2
- data/lib/htm/robot_group.rb +30 -18
- data/lib/htm/sequel_config.rb +215 -0
- data/lib/htm/sql_builder.rb +14 -16
- data/lib/htm/tag_service.rb +78 -0
- data/lib/htm/tasks.rb +3 -0
- data/lib/htm/version.rb +1 -1
- data/lib/htm/workflows/remember_workflow.rb +213 -0
- data/lib/htm.rb +27 -22
- data/lib/tasks/db.rake +0 -2
- data/lib/tasks/doc.rake +2 -2
- data/lib/tasks/files.rake +11 -18
- data/lib/tasks/htm.rake +190 -62
- data/lib/tasks/jobs.rake +179 -54
- data/lib/tasks/tags.rake +8 -13
- data/mkdocs.yml +33 -8
- data/scripts/backfill_parent_tags.rb +376 -0
- data/scripts/normalize_plural_tags.rb +335 -0
- metadata +168 -86
- data/docs/api/yard/HTM/Configuration.md +0 -240
- data/docs/telemetry.md +0 -391
- data/examples/rails_app/app/controllers/tags_controller.rb +0 -30
- data/examples/sinatra_app/Gemfile.lock +0 -166
- data/lib/htm/active_record_config.rb +0 -104
- /data/examples/{config_file_example → 02_config_file_example}/README.md +0 -0
- /data/examples/{config_file_example → 02_config_file_example}/config/htm.local.yml +0 -0
- /data/examples/{config_file_example → 02_config_file_example}/custom_config.yml +0 -0
- /data/examples/{config_file_example → 02_config_file_example}/show_config.rb +0 -0
- /data/examples/{example_app → 06_example_app}/Rakefile +0 -0
- /data/examples/{cli_app → 07_cli_app}/README.md +0 -0
- /data/examples/{sinatra_app → 08_sinatra_app}/Gemfile +0 -0
- /data/examples/{telemetry → 10_telemetry}/README.md +0 -0
- /data/examples/{telemetry → 10_telemetry}/grafana/dashboards/htm-metrics.json +0 -0
- /data/examples/{rails_app → 12_rails_app}/.gitignore +0 -0
- /data/examples/{rails_app → 12_rails_app}/Procfile.dev +0 -0
- /data/examples/{rails_app → 12_rails_app}/README.md +0 -0
- /data/examples/{rails_app → 12_rails_app}/Rakefile +0 -0
- /data/examples/{rails_app → 12_rails_app}/app/assets/stylesheets/application.css +0 -0
- /data/examples/{rails_app → 12_rails_app}/app/assets/stylesheets/inter-font.css +0 -0
- /data/examples/{rails_app → 12_rails_app}/app/controllers/application_controller.rb +0 -0
- /data/examples/{rails_app → 12_rails_app}/app/controllers/search_controller.rb +0 -0
- /data/examples/{rails_app → 12_rails_app}/app/javascript/application.js +0 -0
- /data/examples/{rails_app → 12_rails_app}/app/javascript/controllers/application.js +0 -0
- /data/examples/{rails_app → 12_rails_app}/app/javascript/controllers/index.js +0 -0
- /data/examples/{rails_app → 12_rails_app}/app/views/files/index.html.erb +0 -0
- /data/examples/{rails_app → 12_rails_app}/app/views/files/show.html.erb +0 -0
- /data/examples/{rails_app → 12_rails_app}/app/views/layouts/application.html.erb +0 -0
- /data/examples/{rails_app → 12_rails_app}/app/views/memories/index.html.erb +0 -0
- /data/examples/{rails_app → 12_rails_app}/app/views/memories/new.html.erb +0 -0
- /data/examples/{rails_app → 12_rails_app}/app/views/robots/new.html.erb +0 -0
- /data/examples/{rails_app → 12_rails_app}/app/views/shared/_navbar.html.erb +0 -0
- /data/examples/{rails_app → 12_rails_app}/app/views/shared/_stat_card.html.erb +0 -0
- /data/examples/{rails_app → 12_rails_app}/bin/dev +0 -0
- /data/examples/{rails_app → 12_rails_app}/bin/rails +0 -0
- /data/examples/{rails_app → 12_rails_app}/bin/rake +0 -0
- /data/examples/{rails_app → 12_rails_app}/config/application.rb +0 -0
- /data/examples/{rails_app → 12_rails_app}/config/boot.rb +0 -0
- /data/examples/{rails_app → 12_rails_app}/config/database.yml +0 -0
- /data/examples/{rails_app → 12_rails_app}/config/environment.rb +0 -0
- /data/examples/{rails_app → 12_rails_app}/config/importmap.rb +0 -0
- /data/examples/{rails_app → 12_rails_app}/config/routes.rb +0 -0
- /data/examples/{rails_app → 12_rails_app}/config/tailwind.config.js +0 -0
- /data/examples/{rails_app → 12_rails_app}/config.ru +0 -0
- /data/examples/{rails_app → 12_rails_app}/log/.keep +0 -0
- /data/examples/{rails_app → 12_rails_app}/tmp/local_secret.txt +0 -0
data/lib/htm/config/defaults.yml
CHANGED
|
@@ -91,8 +91,9 @@ defaults:
|
|
|
91
91
|
RULES:
|
|
92
92
|
1. Each concept belongs to ONE path only
|
|
93
93
|
2. Use lowercase, hyphens for multi-word terms
|
|
94
|
-
3.
|
|
95
|
-
4.
|
|
94
|
+
3. ALWAYS use SINGULAR forms, never plurals (user NOT users, framework NOT frameworks, model NOT models)
|
|
95
|
+
4. Return 2-5 tags that best classify this text
|
|
96
|
+
5. Match existing taxonomy paths when applicable
|
|
96
97
|
|
|
97
98
|
TEXT: %{text}
|
|
98
99
|
|
|
@@ -112,27 +113,54 @@ defaults:
|
|
|
112
113
|
provider: ollama
|
|
113
114
|
model: gemma3:latest
|
|
114
115
|
timeout: 180
|
|
115
|
-
enabled:
|
|
116
|
+
enabled: true
|
|
117
|
+
min_length: 10
|
|
118
|
+
max_length: 1000
|
|
119
|
+
min_words: 5
|
|
116
120
|
|
|
117
121
|
system_prompt: |
|
|
118
|
-
You are an atomic fact extraction system.
|
|
119
|
-
Break every statement into its smallest possible factual units.
|
|
122
|
+
You are an atomic fact extraction system. Extract factual propositions from text.
|
|
120
123
|
Output ONLY propositions, one per line, prefixed with a dash (-).
|
|
124
|
+
NEVER ask for clarification or more text - extract what you can from the given text.
|
|
125
|
+
If the text contains no extractable facts, output nothing.
|
|
121
126
|
|
|
122
127
|
user_prompt_template: |
|
|
123
|
-
Extract
|
|
128
|
+
Extract ATOMIC factual propositions from the following text.
|
|
124
129
|
|
|
125
|
-
An atomic proposition
|
|
130
|
+
An atomic proposition:
|
|
131
|
+
- Expresses exactly ONE fact or relationship
|
|
132
|
+
- Is understandable WITHOUT any additional context
|
|
133
|
+
- Uses FULL NAMES, never pronouns (he, she, it, they, this, that)
|
|
134
|
+
- Contains at least 5 words for sufficient context
|
|
126
135
|
|
|
127
|
-
|
|
136
|
+
PRONOUN REPLACEMENT EXAMPLES:
|
|
137
|
+
BAD: "It is important to know the enemy."
|
|
138
|
+
GOOD: "Knowing the enemy is important for spiritual warfare."
|
|
139
|
+
|
|
140
|
+
BAD: "They support thousands of users."
|
|
141
|
+
GOOD: "The Every.to products support thousands of daily users."
|
|
142
|
+
|
|
143
|
+
BAD: "This results in a calculation."
|
|
144
|
+
GOOD: "The age calculation depends on whether the birthday has occurred."
|
|
145
|
+
|
|
146
|
+
CONTEXT ENRICHMENT EXAMPLES:
|
|
147
|
+
BAD: "Wiring costs $1,000."
|
|
148
|
+
GOOD: "Solar panel wiring costs $1,000 for the Oklahoma barndominium project."
|
|
149
|
+
|
|
150
|
+
BAD: "The driveway is gravel."
|
|
151
|
+
GOOD: "Dewayne's barndominium driveway is gravel."
|
|
152
|
+
|
|
153
|
+
RULES:
|
|
128
154
|
1. Split compound statements into separate atomic facts
|
|
129
155
|
2. Each proposition = exactly one fact
|
|
130
|
-
3.
|
|
131
|
-
4.
|
|
156
|
+
3. Replace ALL pronouns with the actual names/nouns they refer to
|
|
157
|
+
4. Include enough context to understand the fact in isolation
|
|
158
|
+
5. If unsure what a pronoun refers to, omit that proposition
|
|
132
159
|
|
|
133
160
|
TEXT: %{text}
|
|
134
161
|
|
|
135
162
|
Return ONLY atomic propositions, one per line. Use a dash (-) prefix for each.
|
|
163
|
+
If you cannot extract any facts, return nothing. Do NOT ask for more text.
|
|
136
164
|
|
|
137
165
|
# ---------------------------------------------------------------------------
|
|
138
166
|
# Chunking Configuration (for file loading)
|
|
@@ -167,14 +195,14 @@ defaults:
|
|
|
167
195
|
# Access: HTM.config.job.backend
|
|
168
196
|
# ---------------------------------------------------------------------------
|
|
169
197
|
job:
|
|
170
|
-
backend:
|
|
198
|
+
backend: fiber
|
|
171
199
|
|
|
172
200
|
# ---------------------------------------------------------------------------
|
|
173
201
|
# General Settings
|
|
174
202
|
# Access: HTM.config.week_start, HTM.config.connection_timeout, etc.
|
|
175
203
|
# ---------------------------------------------------------------------------
|
|
176
204
|
week_start: sunday
|
|
177
|
-
connection_timeout:
|
|
205
|
+
connection_timeout: 60
|
|
178
206
|
telemetry_enabled: false
|
|
179
207
|
log_level: info
|
|
180
208
|
|
|
@@ -197,7 +225,7 @@ defaults:
|
|
|
197
225
|
azure:
|
|
198
226
|
api_key: ~
|
|
199
227
|
endpoint: ~
|
|
200
|
-
api_version:
|
|
228
|
+
api_version: "2024-02-01"
|
|
201
229
|
|
|
202
230
|
ollama:
|
|
203
231
|
url: http://localhost:11434
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class HTM
|
|
4
|
+
# ConfigSection provides method access to nested configuration hashes
|
|
5
|
+
#
|
|
6
|
+
# @example
|
|
7
|
+
# section = ConfigSection.new(host: 'localhost', port: 5432)
|
|
8
|
+
# section.host # => 'localhost'
|
|
9
|
+
# section.port # => 5432
|
|
10
|
+
#
|
|
11
|
+
class ConfigSection
|
|
12
|
+
def initialize(hash = {})
|
|
13
|
+
@data = {}
|
|
14
|
+
(hash || {}).each do |key, value|
|
|
15
|
+
@data[key.to_sym] = value.is_a?(Hash) ? ConfigSection.new(value) : value
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def method_missing(method, *args, &block)
|
|
20
|
+
key = method.to_s
|
|
21
|
+
if key.end_with?('=')
|
|
22
|
+
@data[key.chomp('=').to_sym] = args.first
|
|
23
|
+
elsif @data.key?(method)
|
|
24
|
+
@data[method]
|
|
25
|
+
else
|
|
26
|
+
nil
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def respond_to_missing?(method, include_private = false)
|
|
31
|
+
key = method.to_s.chomp('=').to_sym
|
|
32
|
+
@data.key?(key) || super
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def to_h
|
|
36
|
+
@data.transform_values do |v|
|
|
37
|
+
v.is_a?(ConfigSection) ? v.to_h : v
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def [](key)
|
|
42
|
+
@data[key.to_sym]
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def []=(key, value)
|
|
46
|
+
@data[key.to_sym] = value
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def merge(other)
|
|
50
|
+
other_hash = other.is_a?(ConfigSection) ? other.to_h : other
|
|
51
|
+
ConfigSection.new(deep_merge(to_h, other_hash || {}))
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def keys
|
|
55
|
+
@data.keys
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def each(&block)
|
|
59
|
+
@data.each(&block)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def deep_merge(base, overlay)
|
|
65
|
+
base.merge(overlay) do |_key, old_val, new_val|
|
|
66
|
+
if old_val.is_a?(Hash) && new_val.is_a?(Hash)
|
|
67
|
+
deep_merge(old_val, new_val)
|
|
68
|
+
else
|
|
69
|
+
new_val
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class HTM
|
|
4
|
+
class Config
|
|
5
|
+
module Validator
|
|
6
|
+
SUPPORTED_PROVIDERS = %i[
|
|
7
|
+
openai anthropic gemini azure ollama
|
|
8
|
+
huggingface openrouter bedrock deepseek
|
|
9
|
+
].freeze
|
|
10
|
+
|
|
11
|
+
SUPPORTED_JOB_BACKENDS = %i[active_job sidekiq inline thread fiber].freeze
|
|
12
|
+
SUPPORTED_WEEK_STARTS = %i[sunday monday].freeze
|
|
13
|
+
|
|
14
|
+
def validate_config
|
|
15
|
+
validate_providers
|
|
16
|
+
validate_job_backend
|
|
17
|
+
validate_week_start
|
|
18
|
+
validate_relevance_weights
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def validate_providers
|
|
22
|
+
validate_provider(:embedding_provider, embedding_provider)
|
|
23
|
+
validate_provider(:tag_provider, tag_provider)
|
|
24
|
+
validate_provider(:proposition_provider, proposition_provider)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def validate_provider(name, value)
|
|
28
|
+
return if value.nil?
|
|
29
|
+
|
|
30
|
+
unless SUPPORTED_PROVIDERS.include?(value)
|
|
31
|
+
raise_validation_error("#{name} must be one of: #{SUPPORTED_PROVIDERS.join(', ')} (got #{value.inspect})")
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def validate_job_backend
|
|
36
|
+
return unless job_backend
|
|
37
|
+
|
|
38
|
+
unless SUPPORTED_JOB_BACKENDS.include?(job_backend)
|
|
39
|
+
raise_validation_error("job.backend must be one of: #{SUPPORTED_JOB_BACKENDS.join(', ')} (got #{job_backend.inspect})")
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def validate_week_start
|
|
44
|
+
unless SUPPORTED_WEEK_STARTS.include?(week_start)
|
|
45
|
+
raise_validation_error("week_start must be one of: #{SUPPORTED_WEEK_STARTS.join(', ')} (got #{week_start.inspect})")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def validate_relevance_weights
|
|
50
|
+
total = relevance_semantic_weight + relevance_tag_weight +
|
|
51
|
+
relevance_recency_weight + relevance_access_weight
|
|
52
|
+
|
|
53
|
+
unless (0.99..1.01).cover?(total)
|
|
54
|
+
raise_validation_error("relevance weights must sum to 1.0 (got #{total})")
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def validate_callables
|
|
59
|
+
unless @embedding_generator.respond_to?(:call)
|
|
60
|
+
raise HTM::ValidationError, "embedding_generator must be callable"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
unless @tag_extractor.respond_to?(:call)
|
|
64
|
+
raise HTM::ValidationError, "tag_extractor must be callable"
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
unless @proposition_extractor.respond_to?(:call)
|
|
68
|
+
raise HTM::ValidationError, "proposition_extractor must be callable"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
unless @token_counter.respond_to?(:call)
|
|
72
|
+
raise HTM::ValidationError, "token_counter must be callable"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def validate_logger
|
|
77
|
+
unless @logger.respond_to?(:info) && @logger.respond_to?(:warn) && @logger.respond_to?(:error)
|
|
78
|
+
raise HTM::ValidationError, "logger must respond to :info, :warn, and :error"
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|