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
|
@@ -4,15 +4,21 @@ Client-side embedding generation service for HTM.
|
|
|
4
4
|
|
|
5
5
|
## Overview
|
|
6
6
|
|
|
7
|
-
`HTM::EmbeddingService` generates vector embeddings for text content before database insertion. It
|
|
7
|
+
`HTM::EmbeddingService` generates vector embeddings for text content before database insertion. It uses RubyLLM to support multiple embedding providers:
|
|
8
8
|
|
|
9
|
-
- **Ollama** - Local embedding server (default
|
|
10
|
-
- **OpenAI** - OpenAI's
|
|
9
|
+
- **Ollama** - Local embedding server (default for development)
|
|
10
|
+
- **OpenAI** - OpenAI's embedding models
|
|
11
|
+
- **Anthropic** - For tag extraction (via chat models)
|
|
12
|
+
- **Gemini** - Google's embedding models
|
|
13
|
+
- **Azure** - Azure OpenAI deployments
|
|
14
|
+
- **Bedrock** - AWS Bedrock models
|
|
15
|
+
- **DeepSeek** - DeepSeek embeddings
|
|
11
16
|
|
|
12
17
|
The service also provides token counting for working memory management.
|
|
13
18
|
|
|
14
19
|
**Architecture:**
|
|
15
|
-
- Ruby application generates embeddings via
|
|
20
|
+
- Ruby application generates embeddings via RubyLLM
|
|
21
|
+
- RubyLLM handles provider-specific API calls
|
|
16
22
|
- Embeddings are passed to PostgreSQL during INSERT
|
|
17
23
|
- Simple, reliable, cross-platform operation
|
|
18
24
|
|
|
@@ -34,7 +40,6 @@ Create a new embedding service instance.
|
|
|
34
40
|
HTM::EmbeddingService.new(
|
|
35
41
|
provider = :ollama,
|
|
36
42
|
model: 'nomic-embed-text',
|
|
37
|
-
ollama_url: nil,
|
|
38
43
|
dimensions: nil
|
|
39
44
|
)
|
|
40
45
|
```
|
|
@@ -43,11 +48,12 @@ HTM::EmbeddingService.new(
|
|
|
43
48
|
|
|
44
49
|
| Parameter | Type | Default | Description |
|
|
45
50
|
|-----------|------|---------|-------------|
|
|
46
|
-
| `provider` | Symbol | `:ollama` | Embedding provider (`:ollama`, `:openai`) |
|
|
47
|
-
| `model` | String |
|
|
48
|
-
| `ollama_url` | String, nil | `ENV['OLLAMA_URL']` or `'http://localhost:11434'` | Ollama server URL |
|
|
51
|
+
| `provider` | Symbol | `:ollama` | Embedding provider (`:ollama`, `:openai`, `:gemini`, `:azure`, `:bedrock`, `:deepseek`) |
|
|
52
|
+
| `model` | String | Provider-dependent | Model name for the provider |
|
|
49
53
|
| `dimensions` | Integer, nil | Auto-detected | Expected embedding dimensions |
|
|
50
54
|
|
|
55
|
+
**Provider-specific configuration** is handled via environment variables (see RubyLLM documentation).
|
|
56
|
+
|
|
51
57
|
#### Returns
|
|
52
58
|
|
|
53
59
|
`HTM::EmbeddingService` - Configured embedding service instance
|
|
@@ -58,20 +64,19 @@ HTM::EmbeddingService.new(
|
|
|
58
64
|
|
|
59
65
|
#### Examples
|
|
60
66
|
|
|
61
|
-
**Default Ollama
|
|
67
|
+
**Default configuration (uses Ollama):**
|
|
62
68
|
|
|
63
69
|
```ruby
|
|
64
70
|
service = HTM::EmbeddingService.new
|
|
65
|
-
# Uses Ollama
|
|
71
|
+
# Uses Ollama with nomic-embed-text (768 dimensions)
|
|
66
72
|
```
|
|
67
73
|
|
|
68
|
-
**
|
|
74
|
+
**Ollama with custom model:**
|
|
69
75
|
|
|
70
76
|
```ruby
|
|
71
77
|
service = HTM::EmbeddingService.new(
|
|
72
78
|
:ollama,
|
|
73
79
|
model: 'mxbai-embed-large',
|
|
74
|
-
ollama_url: 'http://localhost:11434',
|
|
75
80
|
dimensions: 1024
|
|
76
81
|
)
|
|
77
82
|
```
|
|
@@ -87,15 +92,27 @@ service = HTM::EmbeddingService.new(
|
|
|
87
92
|
)
|
|
88
93
|
```
|
|
89
94
|
|
|
90
|
-
**
|
|
95
|
+
**Gemini configuration:**
|
|
91
96
|
|
|
92
97
|
```ruby
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
98
|
+
# Requires GEMINI_API_KEY environment variable
|
|
99
|
+
service = HTM::EmbeddingService.new(
|
|
100
|
+
:gemini,
|
|
101
|
+
model: 'text-embedding-004',
|
|
102
|
+
dimensions: 768
|
|
97
103
|
)
|
|
98
|
-
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
**HTM global configuration (recommended):**
|
|
107
|
+
|
|
108
|
+
```ruby
|
|
109
|
+
HTM.configure do |config|
|
|
110
|
+
config.embedding.provider = :openai # or :ollama, :gemini, etc.
|
|
111
|
+
config.embedding.model = 'text-embedding-3-small'
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
htm = HTM.new(robot_name: "Assistant")
|
|
115
|
+
# EmbeddingService configured automatically from global config
|
|
99
116
|
```
|
|
100
117
|
|
|
101
118
|
---
|
|
@@ -144,21 +161,24 @@ begin
|
|
|
144
161
|
embedding = service.embed("some text")
|
|
145
162
|
rescue HTM::EmbeddingError => e
|
|
146
163
|
puts "Embedding failed: #{e.message}"
|
|
147
|
-
#
|
|
164
|
+
# For Ollama: Check if running with `curl http://localhost:11434/api/tags`
|
|
165
|
+
# For cloud providers: Check API key is set correctly
|
|
148
166
|
end
|
|
149
167
|
```
|
|
150
168
|
|
|
151
169
|
#### Implementation Details
|
|
152
170
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
- Requires Ollama server running locally
|
|
171
|
+
All providers are handled through RubyLLM, which provides a consistent interface across providers.
|
|
172
|
+
|
|
173
|
+
**Ollama:** Local HTTP calls, requires Ollama server running
|
|
157
174
|
|
|
158
|
-
**OpenAI
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
175
|
+
**OpenAI:** Cloud API calls, requires `OPENAI_API_KEY`
|
|
176
|
+
|
|
177
|
+
**Gemini:** Cloud API calls, requires `GEMINI_API_KEY`
|
|
178
|
+
|
|
179
|
+
**Azure:** Cloud API calls, requires Azure credentials
|
|
180
|
+
|
|
181
|
+
**Bedrock:** AWS API calls, requires AWS credentials
|
|
162
182
|
|
|
163
183
|
---
|
|
164
184
|
|
|
@@ -207,11 +227,13 @@ htm.add_message(
|
|
|
207
227
|
|
|
208
228
|
## Embedding Providers
|
|
209
229
|
|
|
210
|
-
|
|
230
|
+
HTM uses RubyLLM which supports multiple providers. Choose based on your requirements for privacy, cost, and quality.
|
|
231
|
+
|
|
232
|
+
### Ollama (Default for Development)
|
|
211
233
|
|
|
212
234
|
**Status**: ✅ Fully implemented
|
|
213
235
|
|
|
214
|
-
Local embedding server with various models
|
|
236
|
+
Local embedding server with various models.
|
|
215
237
|
|
|
216
238
|
**Installation:**
|
|
217
239
|
|
|
@@ -234,25 +256,10 @@ ollama pull nomic-embed-text
|
|
|
234
256
|
**Configuration:**
|
|
235
257
|
|
|
236
258
|
```ruby
|
|
237
|
-
|
|
238
|
-
:ollama
|
|
239
|
-
model
|
|
240
|
-
|
|
241
|
-
)
|
|
242
|
-
|
|
243
|
-
embedding = service.embed("test text")
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
**Troubleshooting:**
|
|
247
|
-
|
|
248
|
-
If Ollama is unavailable, embedding generation will fail:
|
|
249
|
-
|
|
250
|
-
```ruby
|
|
251
|
-
# Check Ollama is running
|
|
252
|
-
system("curl http://localhost:11434/api/tags")
|
|
253
|
-
|
|
254
|
-
# Start Ollama if needed
|
|
255
|
-
system("ollama serve")
|
|
259
|
+
HTM.configure do |config|
|
|
260
|
+
config.embedding.provider = :ollama
|
|
261
|
+
config.embedding.model = 'nomic-embed-text'
|
|
262
|
+
end
|
|
256
263
|
```
|
|
257
264
|
|
|
258
265
|
**Advantages:**
|
|
@@ -264,15 +271,14 @@ system("ollama serve")
|
|
|
264
271
|
**Disadvantages:**
|
|
265
272
|
- ❌ Requires local installation
|
|
266
273
|
- ❌ Uses local compute resources
|
|
267
|
-
- ❌ Slightly lower quality than OpenAI
|
|
268
274
|
|
|
269
275
|
---
|
|
270
276
|
|
|
271
|
-
### OpenAI
|
|
277
|
+
### OpenAI (Recommended for Production)
|
|
272
278
|
|
|
273
279
|
**Status**: ✅ Fully implemented
|
|
274
280
|
|
|
275
|
-
Uses OpenAI's embedding API
|
|
281
|
+
Uses OpenAI's embedding API.
|
|
276
282
|
|
|
277
283
|
**Configuration:**
|
|
278
284
|
|
|
@@ -281,13 +287,10 @@ export OPENAI_API_KEY="sk-..."
|
|
|
281
287
|
```
|
|
282
288
|
|
|
283
289
|
```ruby
|
|
284
|
-
|
|
285
|
-
:openai
|
|
286
|
-
model
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
# Add message - embedding generated via OpenAI API
|
|
290
|
-
embedding = service.embed("test text")
|
|
290
|
+
HTM.configure do |config|
|
|
291
|
+
config.embedding.provider = :openai
|
|
292
|
+
config.embedding.model = 'text-embedding-3-small'
|
|
293
|
+
end
|
|
291
294
|
```
|
|
292
295
|
|
|
293
296
|
**Models:**
|
|
@@ -295,20 +298,7 @@ embedding = service.embed("test text")
|
|
|
295
298
|
| Model | Dimensions | Speed | Cost |
|
|
296
299
|
|-------|------------|-------|------|
|
|
297
300
|
| `text-embedding-3-small` | 1536 | Fast | $0.0001/1K tokens |
|
|
298
|
-
| `text-embedding-
|
|
299
|
-
|
|
300
|
-
**Error Handling:**
|
|
301
|
-
|
|
302
|
-
```ruby
|
|
303
|
-
begin
|
|
304
|
-
service = HTM::EmbeddingService.new(:openai)
|
|
305
|
-
embedding = service.embed("test")
|
|
306
|
-
rescue HTM::EmbeddingError => e
|
|
307
|
-
if e.message.include?("API key")
|
|
308
|
-
puts "Set OPENAI_API_KEY environment variable"
|
|
309
|
-
end
|
|
310
|
-
end
|
|
311
|
-
```
|
|
301
|
+
| `text-embedding-3-large` | 3072 | Fast | $0.00013/1K tokens |
|
|
312
302
|
|
|
313
303
|
**Advantages:**
|
|
314
304
|
- ✅ High quality embeddings
|
|
@@ -316,10 +306,44 @@ end
|
|
|
316
306
|
- ✅ Managed service
|
|
317
307
|
|
|
318
308
|
**Disadvantages:**
|
|
319
|
-
- ❌ API costs
|
|
309
|
+
- ❌ API costs
|
|
320
310
|
- ❌ Requires internet connection
|
|
321
|
-
- ❌ Data sent to
|
|
322
|
-
|
|
311
|
+
- ❌ Data sent to cloud
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
### Other Providers
|
|
316
|
+
|
|
317
|
+
**Gemini:**
|
|
318
|
+
```bash
|
|
319
|
+
export GEMINI_API_KEY="..."
|
|
320
|
+
```
|
|
321
|
+
```ruby
|
|
322
|
+
HTM.configure do |config|
|
|
323
|
+
config.embedding.provider = :gemini
|
|
324
|
+
config.embedding.model = 'text-embedding-004'
|
|
325
|
+
end
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
**Azure OpenAI:**
|
|
329
|
+
```bash
|
|
330
|
+
export AZURE_OPENAI_API_KEY="..."
|
|
331
|
+
export AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com"
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
**AWS Bedrock:**
|
|
335
|
+
```bash
|
|
336
|
+
export AWS_ACCESS_KEY_ID="..."
|
|
337
|
+
export AWS_SECRET_ACCESS_KEY="..."
|
|
338
|
+
export AWS_REGION="us-east-1"
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**DeepSeek:**
|
|
342
|
+
```bash
|
|
343
|
+
export DEEPSEEK_API_KEY="..."
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
See the [RubyLLM documentation](https://rubyllm.com/) for complete provider configuration.
|
|
323
347
|
|
|
324
348
|
---
|
|
325
349
|
|
|
@@ -335,15 +359,17 @@ end
|
|
|
335
359
|
system("ollama serve")
|
|
336
360
|
```
|
|
337
361
|
|
|
338
|
-
**
|
|
362
|
+
**API key missing (cloud providers):**
|
|
339
363
|
|
|
340
364
|
```ruby
|
|
341
|
-
# Error:
|
|
365
|
+
# Error: API key not set
|
|
342
366
|
# Solution: Set environment variable
|
|
343
|
-
ENV['OPENAI_API_KEY'] = 'sk-...'
|
|
367
|
+
ENV['OPENAI_API_KEY'] = 'sk-...' # For OpenAI
|
|
368
|
+
ENV['ANTHROPIC_API_KEY'] = 'sk-...' # For Anthropic
|
|
369
|
+
ENV['GEMINI_API_KEY'] = '...' # For Gemini
|
|
344
370
|
```
|
|
345
371
|
|
|
346
|
-
**Invalid model:**
|
|
372
|
+
**Invalid model (Ollama):**
|
|
347
373
|
|
|
348
374
|
```ruby
|
|
349
375
|
# Error: Model not found
|
|
@@ -368,9 +394,10 @@ Based on typical production workloads:
|
|
|
368
394
|
| Ollama | nomic-embed-text | 20ms | 40ms | Free |
|
|
369
395
|
| Ollama | mxbai-embed-large | 30ms | 60ms | Free |
|
|
370
396
|
| OpenAI | text-embedding-3-small | 40ms | 80ms | $0.10 |
|
|
397
|
+
| Gemini | text-embedding-004 | 50ms | 90ms | Varies |
|
|
371
398
|
|
|
372
399
|
**Factors affecting latency:**
|
|
373
|
-
- Network latency (
|
|
400
|
+
- Network latency (local providers vs cloud)
|
|
374
401
|
- Text length (longer text = more tokens = slower)
|
|
375
402
|
- Model size (larger models = slower)
|
|
376
403
|
- System load (CPU/GPU utilization)
|
|
@@ -380,14 +407,17 @@ Based on typical production workloads:
|
|
|
380
407
|
**Use appropriate model size:**
|
|
381
408
|
|
|
382
409
|
```ruby
|
|
383
|
-
# Fast but lower quality
|
|
384
|
-
|
|
410
|
+
# Fast but lower quality (Ollama)
|
|
411
|
+
HTM.configure { |c| c.embedding.model = 'all-minilm' }
|
|
385
412
|
|
|
386
|
-
# Balanced (recommended)
|
|
387
|
-
|
|
413
|
+
# Balanced - Ollama (recommended for development)
|
|
414
|
+
HTM.configure { |c| c.embedding.model = 'nomic-embed-text' }
|
|
388
415
|
|
|
389
|
-
#
|
|
390
|
-
|
|
416
|
+
# High quality - OpenAI (recommended for production)
|
|
417
|
+
HTM.configure do |c|
|
|
418
|
+
c.embedding.provider = :openai
|
|
419
|
+
c.embedding.model = 'text-embedding-3-small'
|
|
420
|
+
end
|
|
391
421
|
```
|
|
392
422
|
|
|
393
423
|
**Batch operations:**
|
|
@@ -410,12 +440,12 @@ end
|
|
|
410
440
|
HTM initializes `EmbeddingService` automatically:
|
|
411
441
|
|
|
412
442
|
```ruby
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
)
|
|
443
|
+
HTM.configure do |config|
|
|
444
|
+
config.embedding.provider = :ollama # or :openai, :gemini, etc.
|
|
445
|
+
config.embedding.model = 'nomic-embed-text'
|
|
446
|
+
end
|
|
418
447
|
|
|
448
|
+
htm = HTM.new(robot_name: "Assistant")
|
|
419
449
|
# EmbeddingService is ready to use internally
|
|
420
450
|
```
|
|
421
451
|
|
|
@@ -426,13 +456,13 @@ sequenceDiagram
|
|
|
426
456
|
participant App as Application
|
|
427
457
|
participant HTM as HTM
|
|
428
458
|
participant ES as EmbeddingService
|
|
429
|
-
participant
|
|
459
|
+
participant LLM as LLM Provider (via RubyLLM)
|
|
430
460
|
participant DB as PostgreSQL
|
|
431
461
|
|
|
432
462
|
App->>HTM: add_message(content)
|
|
433
463
|
HTM->>ES: embed(content)
|
|
434
|
-
ES->>
|
|
435
|
-
|
|
464
|
+
ES->>LLM: Generate embedding
|
|
465
|
+
LLM->>ES: embedding vector
|
|
436
466
|
ES->>HTM: Array<Float>
|
|
437
467
|
HTM->>DB: INSERT with embedding
|
|
438
468
|
DB->>HTM: node_id
|
|
@@ -484,21 +514,20 @@ puts "Token count: #{tokens}"
|
|
|
484
514
|
### Multiple Providers
|
|
485
515
|
|
|
486
516
|
```ruby
|
|
487
|
-
#
|
|
488
|
-
|
|
489
|
-
:ollama
|
|
490
|
-
model
|
|
491
|
-
|
|
517
|
+
# Configure for development (Ollama)
|
|
518
|
+
HTM.configure do |config|
|
|
519
|
+
config.embedding.provider = :ollama
|
|
520
|
+
config.embedding.model = 'nomic-embed-text'
|
|
521
|
+
end
|
|
492
522
|
|
|
493
|
-
#
|
|
494
|
-
|
|
495
|
-
:openai
|
|
496
|
-
model
|
|
497
|
-
|
|
523
|
+
# Configure for production (OpenAI)
|
|
524
|
+
HTM.configure do |config|
|
|
525
|
+
config.embedding.provider = :openai
|
|
526
|
+
config.embedding.model = 'text-embedding-3-small'
|
|
527
|
+
end
|
|
498
528
|
|
|
499
|
-
# Same interface
|
|
500
|
-
|
|
501
|
-
prod_embedding = prod_service.embed("test")
|
|
529
|
+
# Same interface regardless of provider
|
|
530
|
+
embedding = HTM::EmbeddingService.new.embed("test")
|
|
502
531
|
```
|
|
503
532
|
|
|
504
533
|
### Custom Model Dimensions
|
|
@@ -521,6 +550,7 @@ embedding = service.embed("text")
|
|
|
521
550
|
|
|
522
551
|
- [HTM API](htm.md) - Main HTM class
|
|
523
552
|
- [LongTermMemory API](long-term-memory.md) - Storage layer
|
|
524
|
-
- [ADR-003:
|
|
525
|
-
- [
|
|
526
|
-
- [
|
|
553
|
+
- [ADR-003: Default Embedding Provider](../architecture/adrs/003-ollama-embeddings.md) - Architecture decision for defaults
|
|
554
|
+
- [RubyLLM Documentation](https://rubyllm.com/) - Multi-provider LLM interface
|
|
555
|
+
- [Ollama Documentation](https://ollama.ai/docs) - Local LLM provider
|
|
556
|
+
- [OpenAI Embeddings](https://platform.openai.com/docs/guides/embeddings) - Cloud embeddings
|
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
ActiveRecord database configuration and model loading
|
|
6
6
|
|
|
7
|
+
Uses HTM::Config for database settings. Configuration can come from:
|
|
8
|
+
* Environment variables (HTM_DATABASE__URL, HTM_DATABASE__HOST, etc.)
|
|
9
|
+
* Programmatic configuration via HTM.configure
|
|
10
|
+
|
|
7
11
|
|
|
8
12
|
# Class Methods
|
|
9
13
|
## connected?() {: #method-c-connected? }
|
|
@@ -18,6 +22,8 @@ Close all database connections
|
|
|
18
22
|
Establish database connection from HTM::Config
|
|
19
23
|
## load_database_config() {: #method-c-load_database_config }
|
|
20
24
|
Load database configuration from HTM::Config
|
|
25
|
+
**`@return`** [Hash] ActiveRecord-compatible configuration hash
|
|
26
|
+
|
|
21
27
|
## verify_extensions!() {: #method-c-verify_extensions! }
|
|
22
28
|
Verify required extensions are available
|
|
23
29
|
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# Class: HTM::Config
|
|
2
|
+
**Inherits:** Anyway::Config
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
HTM Configuration using Anyway Config
|
|
6
|
+
|
|
7
|
+
Schema is defined in lib/htm/config/defaults.yml (single source of truth)
|
|
8
|
+
Configuration uses nested sections for better organization:
|
|
9
|
+
- HTM.config.database.host
|
|
10
|
+
- HTM.config.embedding.provider
|
|
11
|
+
- HTM.config.providers.openai.api_key
|
|
12
|
+
|
|
13
|
+
Configuration sources (lowest to highest priority):
|
|
14
|
+
1. Bundled defaults: lib/htm/config/defaults.yml (ships with gem)
|
|
15
|
+
2. XDG user config:
|
|
16
|
+
* ~/Library/Application Support/htm/htm.yml (macOS only)
|
|
17
|
+
* ~/.config/htm/htm.yml (XDG default)
|
|
18
|
+
* $XDG_CONFIG_HOME/htm/htm.yml (if XDG_CONFIG_HOME is set)
|
|
19
|
+
3. Project config: ./config/htm.yml (environment-specific)
|
|
20
|
+
4. Local overrides: ./config/htm.local.yml (gitignored)
|
|
21
|
+
5. Environment variables (HTM_*)
|
|
22
|
+
6. Explicit values passed to configure block
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
**`@example`**
|
|
26
|
+
```ruby
|
|
27
|
+
export HTM_EMBEDDING__PROVIDER=openai
|
|
28
|
+
export HTM_EMBEDDING__MODEL=text-embedding-3-small
|
|
29
|
+
export HTM_PROVIDERS__OPENAI__API_KEY=sk-xxx
|
|
30
|
+
```
|
|
31
|
+
**`@example`**
|
|
32
|
+
```ruby
|
|
33
|
+
embedding:
|
|
34
|
+
provider: ollama
|
|
35
|
+
model: nomic-embed-text:latest
|
|
36
|
+
providers:
|
|
37
|
+
ollama:
|
|
38
|
+
url: http://localhost:11434
|
|
39
|
+
```
|
|
40
|
+
**`@example`**
|
|
41
|
+
```ruby
|
|
42
|
+
HTM.configure do |config|
|
|
43
|
+
config.embedding.provider = :openai
|
|
44
|
+
config.embedding.model = 'text-embedding-3-small'
|
|
45
|
+
end
|
|
46
|
+
```
|
|
47
|
+
# Class Methods
|
|
48
|
+
## active_xdg_config_file() {: #method-c-active_xdg_config_file }
|
|
49
|
+
## config_section_with_defaults(section_key ) {: #method-c-config_section_with_defaults }
|
|
50
|
+
Create a coercion that merges incoming value with SCHEMA defaults for a
|
|
51
|
+
section. This ensures env vars like HTM_DATABASE__URL don't lose other
|
|
52
|
+
defaults.
|
|
53
|
+
## deep_merge_hashes(base , overlay ) {: #method-c-deep_merge_hashes }
|
|
54
|
+
Deep merge helper for coercion
|
|
55
|
+
## env() {: #method-c-env }
|
|
56
|
+
## xdg_config_file() {: #method-c-xdg_config_file }
|
|
57
|
+
## xdg_config_paths() {: #method-c-xdg_config_paths }
|
|
58
|
+
XDG Config Path Helpers
|
|
59
|
+
|
|
60
|
+
# Attributes
|
|
61
|
+
## embedding_generator[RW] {: #attribute-i-embedding_generator }
|
|
62
|
+
Callable Accessors (not loaded from config sources)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
## logger[RW] {: #attribute-i-logger }
|
|
66
|
+
Returns the value of attribute logger.
|
|
67
|
+
|
|
68
|
+
## proposition_extractor[RW] {: #attribute-i-proposition_extractor }
|
|
69
|
+
Callable Accessors (not loaded from config sources)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
## tag_extractor[RW] {: #attribute-i-tag_extractor }
|
|
73
|
+
Callable Accessors (not loaded from config sources)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
## token_counter[RW] {: #attribute-i-token_counter }
|
|
77
|
+
Returns the value of attribute token_counter.
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# Instance Methods
|
|
81
|
+
## anthropic_api_key() {: #method-i-anthropic_api_key }
|
|
82
|
+
## azure_api_key() {: #method-i-azure_api_key }
|
|
83
|
+
## azure_api_version() {: #method-i-azure_api_version }
|
|
84
|
+
## azure_endpoint() {: #method-i-azure_endpoint }
|
|
85
|
+
## bedrock_access_key() {: #method-i-bedrock_access_key }
|
|
86
|
+
## bedrock_region() {: #method-i-bedrock_region }
|
|
87
|
+
## bedrock_secret_key() {: #method-i-bedrock_secret_key }
|
|
88
|
+
## chunk_overlap() {: #method-i-chunk_overlap }
|
|
89
|
+
## chunk_size() {: #method-i-chunk_size }
|
|
90
|
+
Chunking convenience accessors
|
|
91
|
+
|
|
92
|
+
## circuit_breaker_failure_threshold() {: #method-i-circuit_breaker_failure_threshold }
|
|
93
|
+
Circuit breaker convenience accessors
|
|
94
|
+
|
|
95
|
+
## circuit_breaker_half_open_max_calls() {: #method-i-circuit_breaker_half_open_max_calls }
|
|
96
|
+
## circuit_breaker_reset_timeout() {: #method-i-circuit_breaker_reset_timeout }
|
|
97
|
+
## configure_ruby_llm(providernil) {: #method-i-configure_ruby_llm }
|
|
98
|
+
## database_config() {: #method-i-database_config }
|
|
99
|
+
## database_configured?() {: #method-i-database_configured? }
|
|
100
|
+
**`@return`** [Boolean]
|
|
101
|
+
|
|
102
|
+
## database_url() {: #method-i-database_url }
|
|
103
|
+
Database convenience methods
|
|
104
|
+
|
|
105
|
+
## deepseek_api_key() {: #method-i-deepseek_api_key }
|
|
106
|
+
## development?() {: #method-i-development? }
|
|
107
|
+
**`@return`** [Boolean]
|
|
108
|
+
|
|
109
|
+
## embedding_dimensions() {: #method-i-embedding_dimensions }
|
|
110
|
+
## embedding_model() {: #method-i-embedding_model }
|
|
111
|
+
## embedding_provider() {: #method-i-embedding_provider }
|
|
112
|
+
Embedding convenience accessors
|
|
113
|
+
|
|
114
|
+
## embedding_timeout() {: #method-i-embedding_timeout }
|
|
115
|
+
## environment() {: #method-i-environment }
|
|
116
|
+
## extract_propositions() {: #method-i-extract_propositions }
|
|
117
|
+
## gemini_api_key() {: #method-i-gemini_api_key }
|
|
118
|
+
## huggingface_api_key() {: #method-i-huggingface_api_key }
|
|
119
|
+
## initialize() {: #method-i-initialize }
|
|
120
|
+
Instance Methods
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
**`@return`** [Config] a new instance of Config
|
|
124
|
+
|
|
125
|
+
## job_backend() {: #method-i-job_backend }
|
|
126
|
+
Job backend convenience accessor
|
|
127
|
+
|
|
128
|
+
## max_embedding_dimension() {: #method-i-max_embedding_dimension }
|
|
129
|
+
## max_tag_depth() {: #method-i-max_tag_depth }
|
|
130
|
+
## normalize_ollama_model(model_name) {: #method-i-normalize_ollama_model }
|
|
131
|
+
Ollama Helpers
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
## ollama_url() {: #method-i-ollama_url }
|
|
135
|
+
## openai_api_key() {: #method-i-openai_api_key }
|
|
136
|
+
Provider credential convenience accessors
|
|
137
|
+
|
|
138
|
+
## openai_organization() {: #method-i-openai_organization }
|
|
139
|
+
## openai_project() {: #method-i-openai_project }
|
|
140
|
+
## openrouter_api_key() {: #method-i-openrouter_api_key }
|
|
141
|
+
## production?() {: #method-i-production? }
|
|
142
|
+
**`@return`** [Boolean]
|
|
143
|
+
|
|
144
|
+
## proposition_model() {: #method-i-proposition_model }
|
|
145
|
+
## proposition_provider() {: #method-i-proposition_provider }
|
|
146
|
+
Proposition convenience accessors
|
|
147
|
+
|
|
148
|
+
## proposition_timeout() {: #method-i-proposition_timeout }
|
|
149
|
+
## refresh_ollama_models!() {: #method-i-refresh_ollama_models! }
|
|
150
|
+
## relevance_access_weight() {: #method-i-relevance_access_weight }
|
|
151
|
+
## relevance_recency_half_life_hours() {: #method-i-relevance_recency_half_life_hours }
|
|
152
|
+
## relevance_recency_weight() {: #method-i-relevance_recency_weight }
|
|
153
|
+
## relevance_semantic_weight() {: #method-i-relevance_semantic_weight }
|
|
154
|
+
Relevance scoring convenience accessors
|
|
155
|
+
|
|
156
|
+
## relevance_tag_weight() {: #method-i-relevance_tag_weight }
|
|
157
|
+
## reset_to_defaults() {: #method-i-reset_to_defaults }
|
|
158
|
+
## service_name() {: #method-i-service_name }
|
|
159
|
+
Service name convenience accessor
|
|
160
|
+
|
|
161
|
+
## tag_model() {: #method-i-tag_model }
|
|
162
|
+
## tag_provider() {: #method-i-tag_provider }
|
|
163
|
+
Tag convenience accessors
|
|
164
|
+
|
|
165
|
+
## tag_timeout() {: #method-i-tag_timeout }
|
|
166
|
+
## test?() {: #method-i-test? }
|
|
167
|
+
Environment Helpers
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
**`@return`** [Boolean]
|
|
171
|
+
|
|
172
|
+
## validate!() {: #method-i-validate! }
|
|
173
|
+
## validate_settings!() {: #method-i-validate_settings! }
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Class: HTM::ConfigSection
|
|
2
|
+
**Inherits:** Object
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
ConfigSection provides method access to nested configuration hashes
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
**`@example`**
|
|
9
|
+
```ruby
|
|
10
|
+
section = ConfigSection.new(host: 'localhost', port: 5432)
|
|
11
|
+
section.host # => 'localhost'
|
|
12
|
+
section.port # => 5432
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
# Instance Methods
|
|
16
|
+
## `[](key)` {: #method-i-[] }
|
|
17
|
+
## `[]=(key, value)` {: #method-i-[]= }
|
|
18
|
+
## `each(&block)` {: #method-i-each }
|
|
19
|
+
## `initialize(hash = {})` {: #method-i-initialize }
|
|
20
|
+
**`@return`** [ConfigSection] a new instance of ConfigSection
|
|
21
|
+
|
|
22
|
+
## `keys()` {: #method-i-keys }
|
|
23
|
+
## `merge(other)` {: #method-i-merge }
|
|
24
|
+
## `method_missing(method, *args, &block)` {: #method-i-method_missing }
|
|
25
|
+
## `respond_to_missing?(method, include_private = false)` {: #method-i-respond_to_missing? }
|
|
26
|
+
**`@return`** [Boolean]
|
|
27
|
+
|
|
28
|
+
## `to_h()` {: #method-i-to_h }
|
|
@@ -8,7 +8,7 @@ initialization
|
|
|
8
8
|
|
|
9
9
|
# Class Methods
|
|
10
10
|
## default_config() {: #method-c-default_config }
|
|
11
|
-
Get default database configuration
|
|
11
|
+
Get default database configuration
|
|
12
12
|
|
|
13
13
|
Uses HTM::Config for database settings.
|
|
14
14
|
**`@return`** [Hash, nil] Connection configuration hash with PG-style keys
|
|
@@ -20,8 +20,8 @@ This railtie automatically configures HTM when Rails boots:
|
|
|
20
20
|
```ruby
|
|
21
21
|
# config/initializers/htm.rb
|
|
22
22
|
HTM.configure do |config|
|
|
23
|
-
config.
|
|
24
|
-
config.
|
|
23
|
+
config.embedding_model = 'custom-model'
|
|
24
|
+
config.tag_model = 'custom-tag-model'
|
|
25
25
|
end
|
|
26
26
|
```
|
|
27
27
|
|