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.
Files changed (216) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +119 -1
  3. data/README.md +12 -0
  4. data/Rakefile +104 -18
  5. data/db/migrate/00001_enable_extensions.rb +9 -5
  6. data/db/migrate/00002_create_robots.rb +18 -6
  7. data/db/migrate/00003_create_file_sources.rb +30 -17
  8. data/db/migrate/00004_create_nodes.rb +60 -48
  9. data/db/migrate/00005_create_tags.rb +24 -12
  10. data/db/migrate/00006_create_node_tags.rb +28 -13
  11. data/db/migrate/00007_create_robot_nodes.rb +40 -26
  12. data/db/schema.sql +17 -1
  13. data/db/seeds.rb +34 -34
  14. data/docs/api/embedding-service.md +140 -110
  15. data/docs/api/yard/HTM/ActiveRecordConfig.md +6 -0
  16. data/docs/api/yard/HTM/Config.md +173 -0
  17. data/docs/api/yard/HTM/ConfigSection.md +28 -0
  18. data/docs/api/yard/HTM/Database.md +1 -1
  19. data/docs/api/yard/HTM/Railtie.md +2 -2
  20. data/docs/api/yard/HTM.md +0 -57
  21. data/docs/api/yard/index.csv +76 -61
  22. data/docs/api/yard-reference.md +2 -1
  23. data/docs/architecture/adrs/003-ollama-embeddings.md +45 -36
  24. data/docs/architecture/adrs/004-hive-mind.md +1 -1
  25. data/docs/architecture/adrs/008-robot-identification.md +1 -1
  26. data/docs/architecture/index.md +11 -9
  27. data/docs/architecture/overview.md +11 -7
  28. data/docs/assets/images/balanced-strategy-decay.svg +41 -0
  29. data/docs/assets/images/class-hierarchy.svg +1 -1
  30. data/docs/assets/images/eviction-priority.svg +43 -0
  31. data/docs/assets/images/exception-hierarchy.svg +2 -2
  32. data/docs/assets/images/hive-mind-shared-memory.svg +52 -0
  33. data/docs/assets/images/htm-architecture-overview.svg +3 -3
  34. data/docs/assets/images/htm-core-components.svg +4 -4
  35. data/docs/assets/images/htm-layered-architecture.svg +1 -1
  36. data/docs/assets/images/htm-memory-addition-flow.svg +2 -2
  37. data/docs/assets/images/htm-memory-recall-flow.svg +2 -2
  38. data/docs/assets/images/memory-topology.svg +53 -0
  39. data/docs/assets/images/two-tier-memory-architecture.svg +55 -0
  40. data/docs/database/naming-convention.md +244 -0
  41. data/docs/database_rake_tasks.md +31 -0
  42. data/docs/development/rake-tasks.md +80 -35
  43. data/docs/development/setup.md +76 -44
  44. data/docs/examples/basic-usage.md +133 -0
  45. data/docs/examples/config-files.md +170 -0
  46. data/docs/examples/file-loading.md +208 -0
  47. data/docs/examples/index.md +116 -0
  48. data/docs/examples/llm-configuration.md +168 -0
  49. data/docs/examples/mcp-client.md +172 -0
  50. data/docs/examples/rails-integration.md +173 -0
  51. data/docs/examples/robot-groups.md +210 -0
  52. data/docs/examples/sinatra-integration.md +218 -0
  53. data/docs/examples/standalone-app.md +216 -0
  54. data/docs/examples/telemetry.md +224 -0
  55. data/docs/examples/timeframes.md +143 -0
  56. data/docs/getting-started/installation.md +97 -40
  57. data/docs/getting-started/quick-start.md +28 -11
  58. data/docs/guides/configuration.md +515 -0
  59. data/docs/guides/file-loading.md +322 -0
  60. data/docs/guides/getting-started.md +40 -9
  61. data/docs/guides/index.md +3 -3
  62. data/docs/guides/mcp-server.md +100 -13
  63. data/docs/guides/propositions.md +264 -0
  64. data/docs/guides/recalling-memories.md +4 -4
  65. data/docs/guides/search-strategies.md +3 -3
  66. data/docs/guides/tags.md +318 -0
  67. data/docs/guides/telemetry.md +229 -0
  68. data/docs/index.md +8 -16
  69. data/docs/{architecture → robots}/hive-mind.md +8 -111
  70. data/docs/robots/index.md +73 -0
  71. data/docs/{guides → robots}/multi-robot.md +3 -3
  72. data/docs/{guides → robots}/robot-groups.md +8 -7
  73. data/docs/{architecture → robots}/two-tier-memory.md +13 -149
  74. data/docs/robots/why-robots.md +85 -0
  75. data/examples/.envrc +6 -0
  76. data/examples/.gitignore +2 -0
  77. data/examples/00_create_examples_db.rb +94 -0
  78. data/examples/{basic_usage.rb → 01_basic_usage.rb} +12 -16
  79. data/examples/{custom_llm_configuration.rb → 03_custom_llm_configuration.rb} +13 -3
  80. data/examples/{file_loader_usage.rb → 04_file_loader_usage.rb} +11 -14
  81. data/examples/{timeframe_demo.rb → 05_timeframe_demo.rb} +10 -3
  82. data/examples/{example_app → 06_example_app}/app.rb +15 -15
  83. data/examples/{cli_app → 07_cli_app}/htm_cli.rb +15 -22
  84. data/examples/08_sinatra_app/Gemfile.lock +241 -0
  85. data/examples/{sinatra_app → 08_sinatra_app}/app.rb +19 -18
  86. data/examples/{mcp_client.rb → 09_mcp_client.rb} +5 -8
  87. data/examples/{telemetry → 10_telemetry}/SETUP_README.md +1 -1
  88. data/examples/{telemetry → 10_telemetry}/demo.rb +14 -10
  89. data/examples/11_robot_groups/README.md +335 -0
  90. data/examples/{robot_groups → 11_robot_groups/lib}/robot_worker.rb +17 -3
  91. data/examples/{robot_groups → 11_robot_groups}/multi_process.rb +9 -9
  92. data/examples/{robot_groups → 11_robot_groups}/same_process.rb +9 -12
  93. data/examples/{rails_app → 12_rails_app}/Gemfile +3 -0
  94. data/examples/{rails_app → 12_rails_app}/Gemfile.lock +87 -58
  95. data/examples/{rails_app → 12_rails_app}/app/controllers/dashboard_controller.rb +10 -6
  96. data/examples/{rails_app → 12_rails_app}/app/controllers/files_controller.rb +5 -5
  97. data/examples/{rails_app → 12_rails_app}/app/controllers/memories_controller.rb +11 -7
  98. data/examples/{rails_app → 12_rails_app}/app/controllers/robots_controller.rb +8 -8
  99. data/examples/12_rails_app/app/controllers/tags_controller.rb +36 -0
  100. data/examples/{rails_app → 12_rails_app}/app/views/dashboard/index.html.erb +2 -2
  101. data/examples/{rails_app → 12_rails_app}/app/views/files/new.html.erb +5 -2
  102. data/examples/{rails_app → 12_rails_app}/app/views/memories/_memory_card.html.erb +3 -3
  103. data/examples/{rails_app → 12_rails_app}/app/views/memories/deleted.html.erb +3 -3
  104. data/examples/{rails_app → 12_rails_app}/app/views/memories/edit.html.erb +3 -3
  105. data/examples/{rails_app → 12_rails_app}/app/views/memories/show.html.erb +4 -4
  106. data/examples/{rails_app → 12_rails_app}/app/views/robots/index.html.erb +2 -2
  107. data/examples/{rails_app → 12_rails_app}/app/views/robots/show.html.erb +4 -4
  108. data/examples/{rails_app → 12_rails_app}/app/views/search/index.html.erb +1 -1
  109. data/examples/{rails_app → 12_rails_app}/app/views/tags/index.html.erb +2 -2
  110. data/examples/{rails_app → 12_rails_app}/app/views/tags/show.html.erb +1 -1
  111. data/examples/12_rails_app/config/initializers/htm.rb +7 -0
  112. data/examples/12_rails_app/config/initializers/rack.rb +5 -0
  113. data/examples/README.md +230 -211
  114. data/examples/examples_helper.rb +138 -0
  115. data/lib/htm/config/builder.rb +167 -0
  116. data/lib/htm/config/database.rb +317 -0
  117. data/lib/htm/config/defaults.yml +41 -13
  118. data/lib/htm/config/section.rb +74 -0
  119. data/lib/htm/config/validator.rb +83 -0
  120. data/lib/htm/config.rb +65 -361
  121. data/lib/htm/database.rb +85 -127
  122. data/lib/htm/errors.rb +14 -0
  123. data/lib/htm/integrations/sinatra.rb +13 -44
  124. data/lib/htm/job_adapter.rb +75 -1
  125. data/lib/htm/jobs/generate_embedding_job.rb +3 -4
  126. data/lib/htm/jobs/generate_propositions_job.rb +4 -5
  127. data/lib/htm/jobs/generate_tags_job.rb +16 -15
  128. data/lib/htm/loaders/defaults_loader.rb +23 -0
  129. data/lib/htm/loaders/markdown_loader.rb +17 -15
  130. data/lib/htm/loaders/xdg_config_loader.rb +9 -9
  131. data/lib/htm/long_term_memory/fulltext_search.rb +14 -14
  132. data/lib/htm/long_term_memory/hybrid_search.rb +396 -229
  133. data/lib/htm/long_term_memory/node_operations.rb +24 -23
  134. data/lib/htm/long_term_memory/relevance_scorer.rb +23 -20
  135. data/lib/htm/long_term_memory/robot_operations.rb +4 -4
  136. data/lib/htm/long_term_memory/tag_operations.rb +91 -77
  137. data/lib/htm/long_term_memory/vector_search.rb +4 -5
  138. data/lib/htm/long_term_memory.rb +13 -13
  139. data/lib/htm/mcp/cli.rb +115 -8
  140. data/lib/htm/mcp/resources.rb +4 -3
  141. data/lib/htm/mcp/server.rb +5 -4
  142. data/lib/htm/mcp/tools.rb +37 -28
  143. data/lib/htm/migration.rb +72 -0
  144. data/lib/htm/models/file_source.rb +52 -31
  145. data/lib/htm/models/node.rb +224 -108
  146. data/lib/htm/models/node_tag.rb +49 -28
  147. data/lib/htm/models/robot.rb +38 -27
  148. data/lib/htm/models/robot_node.rb +63 -35
  149. data/lib/htm/models/tag.rb +126 -123
  150. data/lib/htm/observability.rb +45 -41
  151. data/lib/htm/proposition_service.rb +76 -7
  152. data/lib/htm/railtie.rb +2 -2
  153. data/lib/htm/robot_group.rb +30 -18
  154. data/lib/htm/sequel_config.rb +215 -0
  155. data/lib/htm/sql_builder.rb +14 -16
  156. data/lib/htm/tag_service.rb +78 -0
  157. data/lib/htm/tasks.rb +3 -0
  158. data/lib/htm/version.rb +1 -1
  159. data/lib/htm/workflows/remember_workflow.rb +213 -0
  160. data/lib/htm.rb +27 -22
  161. data/lib/tasks/db.rake +0 -2
  162. data/lib/tasks/doc.rake +2 -2
  163. data/lib/tasks/files.rake +11 -18
  164. data/lib/tasks/htm.rake +190 -62
  165. data/lib/tasks/jobs.rake +179 -54
  166. data/lib/tasks/tags.rake +8 -13
  167. data/mkdocs.yml +33 -8
  168. data/scripts/backfill_parent_tags.rb +376 -0
  169. data/scripts/normalize_plural_tags.rb +335 -0
  170. metadata +168 -86
  171. data/docs/api/yard/HTM/Configuration.md +0 -240
  172. data/docs/telemetry.md +0 -391
  173. data/examples/rails_app/app/controllers/tags_controller.rb +0 -30
  174. data/examples/sinatra_app/Gemfile.lock +0 -166
  175. data/lib/htm/active_record_config.rb +0 -104
  176. /data/examples/{config_file_example → 02_config_file_example}/README.md +0 -0
  177. /data/examples/{config_file_example → 02_config_file_example}/config/htm.local.yml +0 -0
  178. /data/examples/{config_file_example → 02_config_file_example}/custom_config.yml +0 -0
  179. /data/examples/{config_file_example → 02_config_file_example}/show_config.rb +0 -0
  180. /data/examples/{example_app → 06_example_app}/Rakefile +0 -0
  181. /data/examples/{cli_app → 07_cli_app}/README.md +0 -0
  182. /data/examples/{sinatra_app → 08_sinatra_app}/Gemfile +0 -0
  183. /data/examples/{telemetry → 10_telemetry}/README.md +0 -0
  184. /data/examples/{telemetry → 10_telemetry}/grafana/dashboards/htm-metrics.json +0 -0
  185. /data/examples/{rails_app → 12_rails_app}/.gitignore +0 -0
  186. /data/examples/{rails_app → 12_rails_app}/Procfile.dev +0 -0
  187. /data/examples/{rails_app → 12_rails_app}/README.md +0 -0
  188. /data/examples/{rails_app → 12_rails_app}/Rakefile +0 -0
  189. /data/examples/{rails_app → 12_rails_app}/app/assets/stylesheets/application.css +0 -0
  190. /data/examples/{rails_app → 12_rails_app}/app/assets/stylesheets/inter-font.css +0 -0
  191. /data/examples/{rails_app → 12_rails_app}/app/controllers/application_controller.rb +0 -0
  192. /data/examples/{rails_app → 12_rails_app}/app/controllers/search_controller.rb +0 -0
  193. /data/examples/{rails_app → 12_rails_app}/app/javascript/application.js +0 -0
  194. /data/examples/{rails_app → 12_rails_app}/app/javascript/controllers/application.js +0 -0
  195. /data/examples/{rails_app → 12_rails_app}/app/javascript/controllers/index.js +0 -0
  196. /data/examples/{rails_app → 12_rails_app}/app/views/files/index.html.erb +0 -0
  197. /data/examples/{rails_app → 12_rails_app}/app/views/files/show.html.erb +0 -0
  198. /data/examples/{rails_app → 12_rails_app}/app/views/layouts/application.html.erb +0 -0
  199. /data/examples/{rails_app → 12_rails_app}/app/views/memories/index.html.erb +0 -0
  200. /data/examples/{rails_app → 12_rails_app}/app/views/memories/new.html.erb +0 -0
  201. /data/examples/{rails_app → 12_rails_app}/app/views/robots/new.html.erb +0 -0
  202. /data/examples/{rails_app → 12_rails_app}/app/views/shared/_navbar.html.erb +0 -0
  203. /data/examples/{rails_app → 12_rails_app}/app/views/shared/_stat_card.html.erb +0 -0
  204. /data/examples/{rails_app → 12_rails_app}/bin/dev +0 -0
  205. /data/examples/{rails_app → 12_rails_app}/bin/rails +0 -0
  206. /data/examples/{rails_app → 12_rails_app}/bin/rake +0 -0
  207. /data/examples/{rails_app → 12_rails_app}/config/application.rb +0 -0
  208. /data/examples/{rails_app → 12_rails_app}/config/boot.rb +0 -0
  209. /data/examples/{rails_app → 12_rails_app}/config/database.yml +0 -0
  210. /data/examples/{rails_app → 12_rails_app}/config/environment.rb +0 -0
  211. /data/examples/{rails_app → 12_rails_app}/config/importmap.rb +0 -0
  212. /data/examples/{rails_app → 12_rails_app}/config/routes.rb +0 -0
  213. /data/examples/{rails_app → 12_rails_app}/config/tailwind.config.js +0 -0
  214. /data/examples/{rails_app → 12_rails_app}/config.ru +0 -0
  215. /data/examples/{rails_app → 12_rails_app}/log/.keep +0 -0
  216. /data/examples/{rails_app → 12_rails_app}/tmp/local_secret.txt +0 -0
data/docs/telemetry.md DELETED
@@ -1,391 +0,0 @@
1
- # Telemetry (OpenTelemetry Metrics)
2
-
3
- HTM includes optional OpenTelemetry-based metrics for production observability. This document provides detailed configuration and usage information.
4
-
5
- ## Overview
6
-
7
- HTM uses [OpenTelemetry](https://opentelemetry.io/) for metrics collection, the industry-standard observability framework. This provides:
8
-
9
- - **Universal compatibility**: Works with 50+ observability backends
10
- - **Zero vendor lock-in**: Emit standard OTLP, route anywhere
11
- - **Zero overhead when disabled**: Null object pattern ensures no performance impact
12
-
13
- ## Quick Start
14
-
15
- ### 1. Install Dependencies
16
-
17
- Add the OpenTelemetry gems to your Gemfile:
18
-
19
- ```ruby
20
- gem 'opentelemetry-sdk'
21
- gem 'opentelemetry-metrics-sdk'
22
- gem 'opentelemetry-exporter-otlp' # For OTLP export
23
- ```
24
-
25
- ### 2. Enable Telemetry
26
-
27
- ```ruby
28
- HTM.configure do |config|
29
- config.telemetry_enabled = true
30
- end
31
- ```
32
-
33
- Or via environment variable:
34
-
35
- ```bash
36
- export HTM_TELEMETRY_ENABLED="true"
37
- ```
38
-
39
- ### 3. Configure Destination
40
-
41
- Set standard OpenTelemetry environment variables:
42
-
43
- ```bash
44
- export OTEL_METRICS_EXPORTER="otlp"
45
- export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
46
- ```
47
-
48
- ## Configuration Options
49
-
50
- ### HTM Configuration
51
-
52
- | Option | Type | Default | Description |
53
- |--------|------|---------|-------------|
54
- | `telemetry_enabled` | Boolean | `false` | Enable/disable telemetry |
55
-
56
- ```ruby
57
- HTM.configure do |config|
58
- config.telemetry_enabled = true
59
- end
60
- ```
61
-
62
- ### Environment Variables
63
-
64
- #### HTM-specific
65
-
66
- | Variable | Default | Description |
67
- |----------|---------|-------------|
68
- | `HTM_TELEMETRY_ENABLED` | `false` | Enable telemetry (`true`/`false`) |
69
-
70
- #### OpenTelemetry Standard
71
-
72
- These are standard OpenTelemetry environment variables (not HTM-specific):
73
-
74
- | Variable | Example | Description |
75
- |----------|---------|-------------|
76
- | `OTEL_SERVICE_NAME` | `htm` | Service name in telemetry data |
77
- | `OTEL_METRICS_EXPORTER` | `otlp` | Metrics exporter type |
78
- | `OTEL_EXPORTER_OTLP_ENDPOINT` | `http://localhost:4318` | OTLP collector endpoint |
79
- | `OTEL_EXPORTER_OTLP_HEADERS` | `Authorization=Bearer token` | Headers for OTLP requests |
80
-
81
- ## Available Metrics
82
-
83
- ### htm.jobs (Counter)
84
-
85
- Counts job executions by type and outcome.
86
-
87
- **Attributes:**
88
- - `job`: Job type (`embedding`, `tags`)
89
- - `status`: Outcome (`success`, `error`, `circuit_open`)
90
-
91
- **Example queries (PromQL):**
92
- ```promql
93
- # Jobs per minute by type
94
- rate(htm_jobs_total[1m])
95
-
96
- # Error rate for embedding jobs
97
- rate(htm_jobs_total{job="embedding",status="error"}[5m])
98
- / rate(htm_jobs_total{job="embedding"}[5m])
99
- ```
100
-
101
- ### htm.embedding.latency (Histogram)
102
-
103
- Measures embedding generation time in milliseconds.
104
-
105
- **Attributes:**
106
- - `provider`: LLM provider (`ollama`, `openai`, etc.)
107
- - `status`: Outcome (`success`, `error`)
108
-
109
- **Example queries (PromQL):**
110
- ```promql
111
- # p95 embedding latency
112
- histogram_quantile(0.95, rate(htm_embedding_latency_bucket[5m]))
113
-
114
- # Average latency by provider
115
- rate(htm_embedding_latency_sum[5m]) / rate(htm_embedding_latency_count[5m])
116
- ```
117
-
118
- ### htm.tag.latency (Histogram)
119
-
120
- Measures tag extraction time in milliseconds.
121
-
122
- **Attributes:**
123
- - `provider`: LLM provider (`ollama`, `openai`, etc.)
124
- - `status`: Outcome (`success`, `error`)
125
-
126
- **Example queries (PromQL):**
127
- ```promql
128
- # p99 tag extraction latency
129
- histogram_quantile(0.99, rate(htm_tag_latency_bucket[5m]))
130
- ```
131
-
132
- ### htm.search.latency (Histogram)
133
-
134
- Measures search operation time in milliseconds.
135
-
136
- **Attributes:**
137
- - `strategy`: Search strategy (`vector`, `fulltext`, `hybrid`)
138
-
139
- **Example queries (PromQL):**
140
- ```promql
141
- # Search latency by strategy
142
- histogram_quantile(0.95, rate(htm_search_latency_bucket[5m])) by (strategy)
143
-
144
- # Hybrid search avg latency
145
- rate(htm_search_latency_sum{strategy="hybrid"}[5m])
146
- / rate(htm_search_latency_count{strategy="hybrid"}[5m])
147
- ```
148
-
149
- ### htm.cache.operations (Counter)
150
-
151
- Counts cache hits and misses.
152
-
153
- **Attributes:**
154
- - `operation`: Operation type (`hit`, `miss`)
155
-
156
- **Example queries (PromQL):**
157
- ```promql
158
- # Cache hit rate
159
- rate(htm_cache_operations_total{operation="hit"}[5m])
160
- / (rate(htm_cache_operations_total{operation="hit"}[5m])
161
- + rate(htm_cache_operations_total{operation="miss"}[5m]))
162
- ```
163
-
164
- ## Compatible Backends
165
-
166
- HTM metrics work with any OTLP-compatible platform:
167
-
168
- ### Open Source / Self-Hosted
169
-
170
- | Platform | OTLP Support | Notes |
171
- |----------|--------------|-------|
172
- | **Jaeger** | Native (v1.35+) | Distributed tracing with metrics |
173
- | **Prometheus** | Via receiver | Popular metrics platform |
174
- | **Grafana Tempo** | Native | Traces with metrics correlation |
175
- | **Grafana Mimir** | Native | Scalable Prometheus-compatible |
176
- | **SigNoz** | Native | Full-stack observability |
177
- | **Uptrace** | Native | Open source APM |
178
-
179
- ### Commercial / SaaS
180
-
181
- | Platform | OTLP Support | Notes |
182
- |----------|--------------|-------|
183
- | **Datadog** | Native | Full-stack observability |
184
- | **New Relic** | Native | APM and infrastructure |
185
- | **Honeycomb** | Native (preferred) | High-cardinality observability |
186
- | **Splunk APM** | Native | Enterprise observability |
187
- | **Dynatrace** | Native | AI-powered monitoring |
188
- | **AWS X-Ray** | Via ADOT | AWS native tracing |
189
- | **Google Cloud Trace** | Native | GCP native tracing |
190
- | **Azure Monitor** | Native | Azure native monitoring |
191
- | **Grafana Cloud** | Native | Managed Grafana stack |
192
-
193
- ## Setup Examples
194
-
195
- ### Jaeger (Local Development)
196
-
197
- ```bash
198
- # Start Jaeger with OTLP support
199
- docker run -d --name jaeger \
200
- -p 4318:4318 \
201
- -p 16686:16686 \
202
- jaegertracing/all-in-one:latest
203
-
204
- # Configure HTM
205
- export HTM_TELEMETRY_ENABLED="true"
206
- export OTEL_METRICS_EXPORTER="otlp"
207
- export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
208
- ```
209
-
210
- ### Prometheus (via OpenTelemetry Collector)
211
-
212
- ```yaml
213
- # otel-collector-config.yaml
214
- receivers:
215
- otlp:
216
- protocols:
217
- grpc:
218
- http:
219
-
220
- exporters:
221
- prometheus:
222
- endpoint: "0.0.0.0:8889"
223
-
224
- service:
225
- pipelines:
226
- metrics:
227
- receivers: [otlp]
228
- exporters: [prometheus]
229
- ```
230
-
231
- ```bash
232
- docker run -d \
233
- -p 4317:4317 \
234
- -p 4318:4318 \
235
- -p 8889:8889 \
236
- -v $(pwd)/otel-collector-config.yaml:/etc/otel-collector-config.yaml \
237
- otel/opentelemetry-collector:latest \
238
- --config=/etc/otel-collector-config.yaml
239
- ```
240
-
241
- ### Datadog
242
-
243
- ```bash
244
- export HTM_TELEMETRY_ENABLED="true"
245
- export OTEL_METRICS_EXPORTER="otlp"
246
- export OTEL_EXPORTER_OTLP_ENDPOINT="https://otlp.datadoghq.com"
247
- export OTEL_EXPORTER_OTLP_HEADERS="DD-API-KEY=your-api-key"
248
- ```
249
-
250
- ### Honeycomb
251
-
252
- ```bash
253
- export HTM_TELEMETRY_ENABLED="true"
254
- export OTEL_METRICS_EXPORTER="otlp"
255
- export OTEL_EXPORTER_OTLP_ENDPOINT="https://api.honeycomb.io"
256
- export OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=your-api-key"
257
- ```
258
-
259
- ### New Relic
260
-
261
- ```bash
262
- export HTM_TELEMETRY_ENABLED="true"
263
- export OTEL_METRICS_EXPORTER="otlp"
264
- export OTEL_EXPORTER_OTLP_ENDPOINT="https://otlp.nr-data.net"
265
- export OTEL_EXPORTER_OTLP_HEADERS="api-key=your-license-key"
266
- ```
267
-
268
- ## Architecture
269
-
270
- ### Null Object Pattern
271
-
272
- HTM uses a null object pattern for telemetry. When disabled:
273
-
274
- ```ruby
275
- # This code runs identically whether telemetry is enabled or not
276
- HTM::Telemetry.job_counter.add(1, attributes: { 'job' => 'embedding' })
277
- ```
278
-
279
- When telemetry is disabled or the SDK is not installed:
280
- - `HTM::Telemetry.meter` returns a `NullMeter`
281
- - All instruments return `NullInstrument` instances
282
- - All operations (`add`, `record`) are no-ops returning `nil`
283
- - Zero memory allocation, zero CPU overhead
284
-
285
- ### Code Flow
286
-
287
- ![HTM Telemetry Architecture](images/telemetry-architecture.svg)
288
-
289
- ### Instrumentation Points
290
-
291
- HTM instruments these key operations:
292
-
293
- | Component | Metrics Recorded |
294
- |-----------|-----------------|
295
- | `GenerateEmbeddingJob` | `htm.jobs`, `htm.embedding.latency` |
296
- | `GenerateTagsJob` | `htm.jobs`, `htm.tag.latency` |
297
- | `VectorSearch#search` | `htm.search.latency` (strategy: vector) |
298
- | `FulltextSearch#search_fulltext` | `htm.search.latency` (strategy: fulltext) |
299
- | `HybridSearch#search_hybrid` | `htm.search.latency` (strategy: hybrid) |
300
- | `QueryCache#fetch` | `htm.cache.operations` |
301
-
302
- ## Testing
303
-
304
- When writing tests, reset telemetry state between tests:
305
-
306
- ```ruby
307
- def setup
308
- HTM::Telemetry.reset!
309
- HTM.configuration.telemetry_enabled = false
310
- end
311
-
312
- def teardown
313
- HTM::Telemetry.reset!
314
- end
315
- ```
316
-
317
- ### Verifying Metrics in Tests
318
-
319
- ```ruby
320
- def test_records_embedding_latency
321
- # Create a mock histogram
322
- recorded = []
323
- mock_histogram = Object.new
324
- mock_histogram.define_singleton_method(:record) do |value, **kwargs|
325
- recorded << { value: value, attributes: kwargs[:attributes] }
326
- end
327
-
328
- # Inject mock (requires test helper)
329
- HTM::Telemetry.instance_variable_set(:@embedding_latency, mock_histogram)
330
-
331
- # Run operation
332
- HTM::Jobs::GenerateEmbeddingJob.perform(node_id: node.id)
333
-
334
- # Verify
335
- assert recorded.any? { |r| r[:attributes]['status'] == 'success' }
336
- end
337
- ```
338
-
339
- ## Troubleshooting
340
-
341
- ### Metrics Not Appearing
342
-
343
- 1. **Check telemetry is enabled:**
344
- ```ruby
345
- puts HTM.configuration.telemetry_enabled # Should be true
346
- puts HTM::Telemetry.enabled? # Should be true
347
- ```
348
-
349
- 2. **Check SDK is installed:**
350
- ```ruby
351
- puts HTM::Telemetry.sdk_available? # Should be true
352
- ```
353
-
354
- 3. **Check environment variables:**
355
- ```bash
356
- echo $OTEL_METRICS_EXPORTER
357
- echo $OTEL_EXPORTER_OTLP_ENDPOINT
358
- ```
359
-
360
- 4. **Check collector is running:**
361
- ```bash
362
- curl http://localhost:4318/v1/metrics # Should not 404
363
- ```
364
-
365
- ### High Cardinality Issues
366
-
367
- Avoid high-cardinality attributes in metrics. HTM uses low-cardinality attributes by design:
368
-
369
- - `job`: 2-3 values (embedding, tags, propositions)
370
- - `status`: 3 values (success, error, circuit_open)
371
- - `provider`: ~10 values (ollama, openai, etc.)
372
- - `strategy`: 3 values (vector, fulltext, hybrid)
373
- - `operation`: 2 values (hit, miss)
374
-
375
- ### Performance Concerns
376
-
377
- With telemetry disabled (default), there is zero overhead:
378
- - No gem loading
379
- - No object allocation
380
- - No method calls beyond the null check
381
-
382
- With telemetry enabled, overhead is minimal:
383
- - ~1-5μs per metric recording
384
- - Memory for histogram buckets (~1KB per histogram)
385
-
386
- ## References
387
-
388
- - [OpenTelemetry Ruby SDK](https://github.com/open-telemetry/opentelemetry-ruby)
389
- - [OpenTelemetry Metrics SDK](https://github.com/open-telemetry/opentelemetry-ruby/tree/main/metrics_sdk)
390
- - [OpenTelemetry Specification](https://opentelemetry.io/docs/specs/otel/)
391
- - [OTLP Protocol](https://opentelemetry.io/docs/specs/otlp/)
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class TagsController < ApplicationController
4
- def index
5
- @view_type = params[:view] || 'list'
6
-
7
- case @view_type
8
- when 'tree'
9
- @tree_string = HTM::Models::Tag.all.tree_string
10
- @tree_svg = HTM::Models::Tag.all.tree_svg(title: 'HTM Tag Hierarchy')
11
- when 'mermaid'
12
- @tree_mermaid = HTM::Models::Tag.all.tree_mermaid
13
- else
14
- @tags = HTM::Models::Tag
15
- .left_joins(:nodes)
16
- .group('tags.id')
17
- .select('tags.*, COUNT(nodes.id) as node_count')
18
- .order(:name)
19
-
20
- if params[:prefix].present?
21
- @tags = @tags.where('tags.name LIKE ?', "#{params[:prefix]}%")
22
- end
23
- end
24
- end
25
-
26
- def show
27
- @tag = HTM::Models::Tag.find(params[:id])
28
- @memories = @tag.nodes.active.includes(:tags).order(created_at: :desc)
29
- end
30
- end
@@ -1,166 +0,0 @@
1
- PATH
2
- remote: ../..
3
- specs:
4
- htm (0.0.2)
5
- activerecord
6
- lru_redux
7
- neighbor
8
- pg (>= 1.5.0)
9
- ruby_llm
10
- tiktoken_ruby
11
-
12
- GEM
13
- remote: https://rubygems.org/
14
- specs:
15
- activemodel (8.1.1)
16
- activesupport (= 8.1.1)
17
- activerecord (8.1.1)
18
- activemodel (= 8.1.1)
19
- activesupport (= 8.1.1)
20
- timeout (>= 0.4.0)
21
- activesupport (8.1.1)
22
- base64
23
- bigdecimal
24
- concurrent-ruby (~> 1.0, >= 1.3.1)
25
- connection_pool (>= 2.2.5)
26
- drb
27
- i18n (>= 1.6, < 2)
28
- json
29
- logger (>= 1.4.2)
30
- minitest (>= 5.1)
31
- securerandom (>= 0.3)
32
- tzinfo (~> 2.0, >= 2.0.5)
33
- uri (>= 0.13.1)
34
- base64 (0.3.0)
35
- bigdecimal (3.3.1)
36
- concurrent-ruby (1.3.5)
37
- connection_pool (2.5.5)
38
- drb (2.2.3)
39
- event_stream_parser (1.0.0)
40
- faraday (2.14.0)
41
- faraday-net_http (>= 2.0, < 3.5)
42
- json
43
- logger
44
- faraday-multipart (1.1.1)
45
- multipart-post (~> 2.0)
46
- faraday-net_http (3.4.2)
47
- net-http (~> 0.5)
48
- faraday-retry (2.3.2)
49
- faraday (~> 2.0)
50
- ffi (1.17.2-aarch64-linux-gnu)
51
- ffi (1.17.2-aarch64-linux-musl)
52
- ffi (1.17.2-arm-linux-gnu)
53
- ffi (1.17.2-arm-linux-musl)
54
- ffi (1.17.2-arm64-darwin)
55
- ffi (1.17.2-x86_64-darwin)
56
- ffi (1.17.2-x86_64-linux-gnu)
57
- ffi (1.17.2-x86_64-linux-musl)
58
- i18n (1.14.7)
59
- concurrent-ruby (~> 1.0)
60
- json (2.16.0)
61
- listen (3.9.0)
62
- rb-fsevent (~> 0.10, >= 0.10.3)
63
- rb-inotify (~> 0.9, >= 0.9.10)
64
- logger (1.7.0)
65
- lru_redux (1.1.0)
66
- marcel (1.1.0)
67
- minitest (5.26.2)
68
- multi_json (1.17.0)
69
- multipart-post (2.4.1)
70
- mustermann (3.0.4)
71
- ruby2_keywords (~> 0.0.1)
72
- neighbor (0.6.0)
73
- activerecord (>= 7.1)
74
- net-http (0.8.0)
75
- uri (>= 0.11.1)
76
- nio4r (2.7.5)
77
- pg (1.6.2)
78
- pg (1.6.2-aarch64-linux)
79
- pg (1.6.2-aarch64-linux-musl)
80
- pg (1.6.2-arm64-darwin)
81
- pg (1.6.2-x86_64-darwin)
82
- pg (1.6.2-x86_64-linux)
83
- pg (1.6.2-x86_64-linux-musl)
84
- puma (6.6.1)
85
- nio4r (~> 2.0)
86
- rack (2.2.21)
87
- rack-protection (3.2.0)
88
- base64 (>= 0.1.0)
89
- rack (~> 2.2, >= 2.2.4)
90
- rb-fsevent (0.11.2)
91
- rb-inotify (0.11.1)
92
- ffi (~> 1.0)
93
- redis (5.4.1)
94
- redis-client (>= 0.22.0)
95
- redis-client (0.26.1)
96
- connection_pool
97
- rerun (0.14.0)
98
- listen (~> 3.0)
99
- ruby2_keywords (0.0.5)
100
- ruby_llm (1.9.1)
101
- base64
102
- event_stream_parser (~> 1)
103
- faraday (>= 1.10.0)
104
- faraday-multipart (>= 1)
105
- faraday-net_http (>= 1)
106
- faraday-retry (>= 1)
107
- marcel (~> 1.0)
108
- ruby_llm-schema (~> 0.2.1)
109
- zeitwerk (~> 2)
110
- ruby_llm-schema (0.2.5)
111
- securerandom (0.4.1)
112
- sidekiq (7.3.9)
113
- base64
114
- connection_pool (>= 2.3.0)
115
- logger
116
- rack (>= 2.2.4)
117
- redis-client (>= 0.22.2)
118
- sinatra (3.2.0)
119
- mustermann (~> 3.0)
120
- rack (~> 2.2, >= 2.2.4)
121
- rack-protection (= 3.2.0)
122
- tilt (~> 2.0)
123
- sinatra-contrib (3.2.0)
124
- multi_json (>= 0.0.2)
125
- mustermann (~> 3.0)
126
- rack-protection (= 3.2.0)
127
- sinatra (= 3.2.0)
128
- tilt (~> 2.0)
129
- tiktoken_ruby (0.0.13-aarch64-linux)
130
- tiktoken_ruby (0.0.13-arm-linux)
131
- tiktoken_ruby (0.0.13-arm64-darwin)
132
- tiktoken_ruby (0.0.13-x86_64-darwin)
133
- tiktoken_ruby (0.0.13-x86_64-linux)
134
- tiktoken_ruby (0.0.13-x86_64-linux-musl)
135
- tilt (2.6.1)
136
- timeout (0.4.4)
137
- tzinfo (2.0.6)
138
- concurrent-ruby (~> 1.0)
139
- uri (1.1.1)
140
- zeitwerk (2.7.3)
141
-
142
- PLATFORMS
143
- aarch64-linux
144
- aarch64-linux-gnu
145
- aarch64-linux-musl
146
- arm-linux
147
- arm-linux-gnu
148
- arm-linux-musl
149
- arm64-darwin
150
- x86_64-darwin
151
- x86_64-linux
152
- x86_64-linux-gnu
153
- x86_64-linux-musl
154
-
155
- DEPENDENCIES
156
- htm!
157
- multi_json
158
- puma (~> 6.0)
159
- redis (~> 5.0)
160
- rerun
161
- sidekiq (~> 7.0)
162
- sinatra (~> 3.0)
163
- sinatra-contrib (~> 3.0)
164
-
165
- BUNDLED WITH
166
- 2.7.2
@@ -1,104 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'active_record'
4
- require 'pg'
5
- require 'neighbor'
6
-
7
- class HTM
8
- # ActiveRecord database configuration and model loading
9
- #
10
- # Uses HTM::Config for database settings. Configuration can come from:
11
- # - Environment variables (HTM_DATABASE__URL, HTM_DATABASE__HOST, etc.)
12
- # - Programmatic configuration via HTM.configure
13
- #
14
- class ActiveRecordConfig
15
- class << self
16
- # Establish database connection from HTM::Config
17
- def establish_connection!
18
- config = load_database_config
19
-
20
- ActiveRecord::Base.establish_connection(config)
21
-
22
- # Set search path
23
- ActiveRecord::Base.connection.execute("SET search_path TO public")
24
-
25
- # Load models after connection is established
26
- require_models
27
-
28
- true
29
- end
30
-
31
- # Load database configuration from HTM::Config
32
- #
33
- # @return [Hash] ActiveRecord-compatible configuration hash
34
- #
35
- def load_database_config
36
- HTM.config.database_config
37
- end
38
-
39
- # Check if connection is established and active
40
- def connected?
41
- return false unless defined?(ActiveRecord::Base)
42
- return false unless ActiveRecord::Base.connection_handler.connection_pool_list.any?
43
-
44
- ActiveRecord::Base.connected? && ActiveRecord::Base.connection.active?
45
- rescue ActiveRecord::ConnectionNotDefined, ActiveRecord::ConnectionNotEstablished
46
- false
47
- rescue StandardError
48
- false
49
- end
50
-
51
- # Close all database connections
52
- def disconnect!
53
- ActiveRecord::Base.connection_pool.disconnect!
54
- end
55
-
56
- # Verify required extensions are available
57
- def verify_extensions!
58
- conn = ActiveRecord::Base.connection
59
-
60
- required_extensions = {
61
- 'vector' => 'pgvector extension',
62
- 'pg_trgm' => 'PostgreSQL trigram extension'
63
- }
64
-
65
- missing = []
66
- required_extensions.each do |ext, name|
67
- result = conn.select_value(
68
- "SELECT COUNT(*) FROM pg_extension WHERE extname = '#{ext}'"
69
- )
70
- missing << name if result.to_i.zero?
71
- end
72
-
73
- if missing.any?
74
- raise "Missing required PostgreSQL extensions: #{missing.join(', ')}"
75
- end
76
-
77
- true
78
- end
79
-
80
- # Get connection pool statistics
81
- def connection_stats
82
- pool = ActiveRecord::Base.connection_pool
83
- {
84
- size: pool.size,
85
- connections: pool.connections.size,
86
- in_use: pool.connections.count(&:in_use?),
87
- available: pool.connections.count { |c| !c.in_use? }
88
- }
89
- end
90
-
91
- private
92
-
93
- # Require all model files
94
- def require_models
95
- require_relative 'models/robot'
96
- require_relative 'models/node'
97
- require_relative 'models/robot_node'
98
- require_relative 'models/tag'
99
- require_relative 'models/node_tag'
100
- require_relative 'models/file_source'
101
- end
102
- end
103
- end
104
- end
File without changes
File without changes
File without changes
File without changes
File without changes