htm 0.0.11 → 0.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.dictate.toml +46 -0
  3. data/.envrc +2 -0
  4. data/CHANGELOG.md +85 -2
  5. data/README.md +348 -79
  6. data/Rakefile +14 -2
  7. data/bin/htm_mcp.rb +94 -0
  8. data/config/database.yml +20 -13
  9. data/db/migrate/00003_create_file_sources.rb +5 -0
  10. data/db/migrate/00004_create_nodes.rb +17 -0
  11. data/db/migrate/00005_create_tags.rb +7 -0
  12. data/db/migrate/00006_create_node_tags.rb +2 -0
  13. data/db/migrate/00007_create_robot_nodes.rb +7 -0
  14. data/db/schema.sql +69 -100
  15. data/docs/api/index.md +1 -1
  16. data/docs/api/yard/HTM/Configuration.md +54 -0
  17. data/docs/api/yard/HTM/Database.md +13 -10
  18. data/docs/api/yard/HTM/EmbeddingService.md +5 -1
  19. data/docs/api/yard/HTM/LongTermMemory.md +18 -277
  20. data/docs/api/yard/HTM/PropositionError.md +18 -0
  21. data/docs/api/yard/HTM/PropositionService.md +66 -0
  22. data/docs/api/yard/HTM/QueryCache.md +88 -0
  23. data/docs/api/yard/HTM/RobotGroup.md +481 -0
  24. data/docs/api/yard/HTM/SqlBuilder.md +108 -0
  25. data/docs/api/yard/HTM/TagService.md +4 -0
  26. data/docs/api/yard/HTM/Telemetry/NullInstrument.md +13 -0
  27. data/docs/api/yard/HTM/Telemetry/NullMeter.md +15 -0
  28. data/docs/api/yard/HTM/Telemetry.md +109 -0
  29. data/docs/api/yard/HTM/WorkingMemoryChannel.md +176 -0
  30. data/docs/api/yard/HTM.md +8 -22
  31. data/docs/api/yard/index.csv +102 -25
  32. data/docs/api/yard-reference.md +8 -0
  33. data/docs/architecture/index.md +1 -1
  34. data/docs/assets/images/multi-provider-failover.svg +51 -0
  35. data/docs/assets/images/robot-group-architecture.svg +65 -0
  36. data/docs/database/README.md +3 -3
  37. data/docs/database/public.file_sources.svg +29 -21
  38. data/docs/database/public.node_tags.md +2 -0
  39. data/docs/database/public.node_tags.svg +53 -41
  40. data/docs/database/public.nodes.md +2 -0
  41. data/docs/database/public.nodes.svg +52 -40
  42. data/docs/database/public.robot_nodes.md +2 -0
  43. data/docs/database/public.robot_nodes.svg +30 -22
  44. data/docs/database/public.robots.svg +16 -12
  45. data/docs/database/public.tags.md +3 -0
  46. data/docs/database/public.tags.svg +41 -33
  47. data/docs/database/schema.json +66 -0
  48. data/docs/database/schema.svg +60 -48
  49. data/docs/development/index.md +14 -1
  50. data/docs/development/rake-tasks.md +1068 -0
  51. data/docs/getting-started/index.md +1 -1
  52. data/docs/getting-started/quick-start.md +144 -155
  53. data/docs/guides/adding-memories.md +2 -3
  54. data/docs/guides/context-assembly.md +185 -184
  55. data/docs/guides/getting-started.md +154 -148
  56. data/docs/guides/index.md +8 -1
  57. data/docs/guides/long-term-memory.md +60 -92
  58. data/docs/guides/mcp-server.md +617 -0
  59. data/docs/guides/multi-robot.md +249 -345
  60. data/docs/guides/recalling-memories.md +153 -163
  61. data/docs/guides/robot-groups.md +604 -0
  62. data/docs/guides/search-strategies.md +61 -58
  63. data/docs/guides/working-memory.md +103 -136
  64. data/docs/images/telemetry-architecture.svg +153 -0
  65. data/docs/index.md +30 -26
  66. data/docs/telemetry.md +391 -0
  67. data/examples/README.md +46 -1
  68. data/examples/cli_app/README.md +1 -1
  69. data/examples/cli_app/htm_cli.rb +1 -1
  70. data/examples/robot_groups/robot_worker.rb +1 -2
  71. data/examples/robot_groups/same_process.rb +1 -4
  72. data/examples/sinatra_app/app.rb +1 -1
  73. data/examples/telemetry/README.md +147 -0
  74. data/examples/telemetry/SETUP_README.md +169 -0
  75. data/examples/telemetry/demo.rb +498 -0
  76. data/examples/telemetry/grafana/dashboards/htm-metrics.json +457 -0
  77. data/lib/htm/configuration.rb +261 -70
  78. data/lib/htm/database.rb +46 -22
  79. data/lib/htm/embedding_service.rb +24 -14
  80. data/lib/htm/errors.rb +15 -1
  81. data/lib/htm/jobs/generate_embedding_job.rb +19 -0
  82. data/lib/htm/jobs/generate_propositions_job.rb +103 -0
  83. data/lib/htm/jobs/generate_tags_job.rb +24 -0
  84. data/lib/htm/loaders/markdown_chunker.rb +79 -0
  85. data/lib/htm/loaders/markdown_loader.rb +41 -15
  86. data/lib/htm/long_term_memory/fulltext_search.rb +138 -0
  87. data/lib/htm/long_term_memory/hybrid_search.rb +324 -0
  88. data/lib/htm/long_term_memory/node_operations.rb +209 -0
  89. data/lib/htm/long_term_memory/relevance_scorer.rb +355 -0
  90. data/lib/htm/long_term_memory/robot_operations.rb +34 -0
  91. data/lib/htm/long_term_memory/tag_operations.rb +428 -0
  92. data/lib/htm/long_term_memory/vector_search.rb +109 -0
  93. data/lib/htm/long_term_memory.rb +51 -1153
  94. data/lib/htm/models/node.rb +35 -2
  95. data/lib/htm/models/node_tag.rb +31 -0
  96. data/lib/htm/models/robot_node.rb +31 -0
  97. data/lib/htm/models/tag.rb +44 -0
  98. data/lib/htm/proposition_service.rb +169 -0
  99. data/lib/htm/query_cache.rb +214 -0
  100. data/lib/htm/robot_group.rb +721 -0
  101. data/lib/htm/sql_builder.rb +178 -0
  102. data/lib/htm/tag_service.rb +16 -6
  103. data/lib/htm/tasks.rb +8 -2
  104. data/lib/htm/telemetry.rb +224 -0
  105. data/lib/htm/version.rb +1 -1
  106. data/lib/htm/working_memory_channel.rb +250 -0
  107. data/lib/htm.rb +66 -3
  108. data/lib/tasks/doc.rake +1 -1
  109. data/lib/tasks/htm.rake +259 -13
  110. data/mkdocs.yml +98 -96
  111. metadata +55 -20
  112. data/.aigcm_msg +0 -1
  113. data/.claude/settings.local.json +0 -95
  114. data/CLAUDE.md +0 -603
  115. data/db/migrate/00009_add_working_memory_to_robot_nodes.rb +0 -12
  116. data/examples/cli_app/temp.log +0 -93
  117. data/examples/robot_groups/lib/robot_group.rb +0 -419
  118. data/examples/robot_groups/lib/working_memory_channel.rb +0 -140
  119. data/lib/htm/loaders/paragraph_chunker.rb +0 -112
  120. data/notes/ARCHITECTURE_REVIEW.md +0 -1167
  121. data/notes/IMPLEMENTATION_SUMMARY.md +0 -606
  122. data/notes/MULTI_FRAMEWORK_IMPLEMENTATION.md +0 -451
  123. data/notes/next_steps.md +0 -100
  124. data/notes/plan.md +0 -627
  125. data/notes/tag_ontology_enhancement_ideas.md +0 -222
  126. data/notes/timescaledb_removal_summary.md +0 -200
@@ -81,6 +81,21 @@ Returns the value of attribute bedrock_region.
81
81
  ## bedrock_secret_key[RW] {: #attribute-i-bedrock_secret_key }
82
82
  Returns the value of attribute bedrock_secret_key.
83
83
 
84
+ ## chunk_overlap[RW] {: #attribute-i-chunk_overlap }
85
+ Character overlap between chunks (default: 64)
86
+
87
+ ## chunk_size[RW] {: #attribute-i-chunk_size }
88
+ Chunking configuration (for file loading)
89
+
90
+ ## circuit_breaker_failure_threshold[RW] {: #attribute-i-circuit_breaker_failure_threshold }
91
+ Circuit breaker configuration
92
+
93
+ ## circuit_breaker_half_open_max_calls[RW] {: #attribute-i-circuit_breaker_half_open_max_calls }
94
+ Successes to close (default: 3)
95
+
96
+ ## circuit_breaker_reset_timeout[RW] {: #attribute-i-circuit_breaker_reset_timeout }
97
+ Seconds before half-open (default: 60)
98
+
84
99
  ## connection_timeout[RW] {: #attribute-i-connection_timeout }
85
100
  Returns the value of attribute connection_timeout.
86
101
 
@@ -102,6 +117,9 @@ Returns the value of attribute embedding_provider.
102
117
  ## embedding_timeout[RW] {: #attribute-i-embedding_timeout }
103
118
  Returns the value of attribute embedding_timeout.
104
119
 
120
+ ## extract_propositions[RW] {: #attribute-i-extract_propositions }
121
+ Returns the value of attribute extract_propositions.
122
+
105
123
  ## gemini_api_key[RW] {: #attribute-i-gemini_api_key }
106
124
  Returns the value of attribute gemini_api_key.
107
125
 
@@ -114,6 +132,12 @@ Returns the value of attribute job_backend.
114
132
  ## logger[RW] {: #attribute-i-logger }
115
133
  Returns the value of attribute logger.
116
134
 
135
+ ## max_embedding_dimension[RW] {: #attribute-i-max_embedding_dimension }
136
+ Limit configuration
137
+
138
+ ## max_tag_depth[RW] {: #attribute-i-max_tag_depth }
139
+ Max tag hierarchy depth (default: 4)
140
+
117
141
  ## ollama_url[RW] {: #attribute-i-ollama_url }
118
142
  Returns the value of attribute ollama_url.
119
143
 
@@ -129,6 +153,33 @@ Provider-specific API keys and endpoints
129
153
  ## openrouter_api_key[RW] {: #attribute-i-openrouter_api_key }
130
154
  Returns the value of attribute openrouter_api_key.
131
155
 
156
+ ## proposition_extractor[RW] {: #attribute-i-proposition_extractor }
157
+ Returns the value of attribute proposition_extractor.
158
+
159
+ ## proposition_model[RW] {: #attribute-i-proposition_model }
160
+ Returns the value of attribute proposition_model.
161
+
162
+ ## proposition_provider[RW] {: #attribute-i-proposition_provider }
163
+ Returns the value of attribute proposition_provider.
164
+
165
+ ## proposition_timeout[RW] {: #attribute-i-proposition_timeout }
166
+ Returns the value of attribute proposition_timeout.
167
+
168
+ ## relevance_access_weight[RW] {: #attribute-i-relevance_access_weight }
169
+ Access frequency weight (default: 0.1)
170
+
171
+ ## relevance_recency_half_life_hours[RW] {: #attribute-i-relevance_recency_half_life_hours }
172
+ Decay half-life in hours (default: 168 = 1 week)
173
+
174
+ ## relevance_recency_weight[RW] {: #attribute-i-relevance_recency_weight }
175
+ Temporal freshness weight (default: 0.1)
176
+
177
+ ## relevance_semantic_weight[RW] {: #attribute-i-relevance_semantic_weight }
178
+ Relevance scoring weights (must sum to 1.0)
179
+
180
+ ## relevance_tag_weight[RW] {: #attribute-i-relevance_tag_weight }
181
+ Tag overlap weight (default: 0.3)
182
+
132
183
  ## tag_extractor[RW] {: #attribute-i-tag_extractor }
133
184
  Returns the value of attribute tag_extractor.
134
185
 
@@ -141,6 +192,9 @@ Returns the value of attribute tag_provider.
141
192
  ## tag_timeout[RW] {: #attribute-i-tag_timeout }
142
193
  Returns the value of attribute tag_timeout.
143
194
 
195
+ ## telemetry_enabled[RW] {: #attribute-i-telemetry_enabled }
196
+ Enable OpenTelemetry metrics (default: false)
197
+
144
198
  ## token_counter[RW] {: #attribute-i-token_counter }
145
199
  Returns the value of attribute token_counter.
146
200
 
@@ -8,20 +8,23 @@ initialization
8
8
 
9
9
  # Class Methods
10
10
  ## default_config() {: #method-c-default_config }
11
- Get default database configuration
12
- **`@return`** [Hash, nil] Connection configuration hash
11
+ Get default database configuration (respects RAILS_ENV)
12
+
13
+ Uses ActiveRecordConfig which reads from config/database.yml and respects
14
+ RAILS_ENV for environment-specific database selection.
15
+ **`@return`** [Hash, nil] Connection configuration hash with PG-style keys
13
16
 
14
17
  ## drop(db_url nil) {: #method-c-drop }
15
- Drop all HTM tables
16
- **`@param`** [String] Database connection URL (uses ENV['HTM_DBURL'] if not provided)
18
+ Drop all HTM tables (respects RAILS_ENV)
19
+ **`@param`** [String] Database connection URL (uses default_config if not provided)
17
20
 
18
21
  **`@return`** [void]
19
22
 
20
23
  ## dump_schema(db_url nil) {: #method-c-dump_schema }
21
- Dump current database schema to db/schema.sql
24
+ Dump current database schema to db/schema.sql (respects RAILS_ENV)
22
25
 
23
26
  Uses pg_dump to create a clean SQL schema file without data
24
- **`@param`** [String] Database connection URL (uses ENV['HTM_DBURL'] if not provided)
27
+ **`@param`** [String] Database connection URL (uses default_config if not provided)
25
28
 
26
29
  **`@return`** [void]
27
30
 
@@ -39,16 +42,16 @@ comprehensive database documentation including:
39
42
  **`@return`** [void]
40
43
 
41
44
  ## info(db_url nil) {: #method-c-info }
42
- Show database info
43
- **`@param`** [String] Database connection URL (uses ENV['HTM_DBURL'] if not provided)
45
+ Show database info (respects RAILS_ENV)
46
+ **`@param`** [String] Database connection URL (uses default_config if not provided)
44
47
 
45
48
  **`@return`** [void]
46
49
 
47
50
  ## load_schema(db_url nil) {: #method-c-load_schema }
48
- Load schema from db/schema.sql
51
+ Load schema from db/schema.sql (respects RAILS_ENV)
49
52
 
50
53
  Uses psql to load the schema file
51
- **`@param`** [String] Database connection URL (uses ENV['HTM_DBURL'] if not provided)
54
+ **`@param`** [String] Database connection URL (uses default_config if not provided)
52
55
 
53
56
  **`@return`** [void]
54
57
 
@@ -39,8 +39,12 @@ Generate embedding with validation and processing
39
39
  storage_dimension: Integer # Padded dimension (2000)
40
40
  }
41
41
 
42
+ ## max_dimension() {: #method-c-max_dimension }
43
+ Maximum embedding dimension (configurable, default 2000)
44
+ **`@return`** [Integer] Max dimensions for pgvector HNSW index
45
+
42
46
  ## pad_embedding(embedding ) {: #method-c-pad_embedding }
43
- Pad embedding to MAX_DIMENSION with zeros
47
+ Pad embedding to max_dimension with zeros
44
48
  **`@param`** [Array<Float>] Original embedding
45
49
 
46
50
  **`@return`** [Array<Float>] Padded embedding
@@ -1,6 +1,8 @@
1
1
  # Class: HTM::LongTermMemory
2
2
  **Inherits:** Object
3
3
 
4
+ **Includes:** FulltextSearch, HybridSearch, NodeOperations, RelevanceScorer, RobotOperations, TagOperations, VectorSearch
5
+
4
6
 
5
7
  Long-term Memory - PostgreSQL/TimescaleDB-backed permanent storage
6
8
 
@@ -13,6 +15,21 @@ LongTermMemory provides durable storage for all memory nodes with:
13
15
  * ActiveRecord ORM for data access
14
16
  * Query result caching for efficiency
15
17
 
18
+ This class uses standalone utility classes and modules:
19
+
20
+ Standalone classes (used via class methods or instances):
21
+ * HTM::SqlBuilder: SQL condition building helpers (class methods)
22
+ * HTM::QueryCache: Query result caching (instantiated as @cache)
23
+
24
+ Included modules:
25
+ * RelevanceScorer: Dynamic relevance scoring
26
+ * NodeOperations: Node CRUD operations
27
+ * RobotOperations: Robot registration and activity
28
+ * TagOperations: Tag management
29
+ * VectorSearch: Vector similarity search
30
+ * FulltextSearch: Full-text search
31
+ * HybridSearch: Combined search strategies
32
+
16
33
 
17
34
  # Attributes
18
35
  ## query_timeout[RW] {: #attribute-i-query_timeout }
@@ -20,104 +37,11 @@ Returns the value of attribute query_timeout.
20
37
 
21
38
 
22
39
  # Instance Methods
23
- ## add(content:, token_count:0, robot_id:, embedding:nil, metadata:{}) {: #method-i-add }
24
- Add a node to long-term memory (with deduplication)
25
-
26
- If content already exists (by content_hash), links the robot to the existing
27
- node and updates timestamps. Otherwise creates a new node.
28
-
29
- **`@param`** [String] Conversation message/utterance
30
-
31
- **`@param`** [Integer] Token count
32
-
33
- **`@param`** [Integer] Robot identifier
34
-
35
- **`@param`** [Array<Float>, nil] Pre-generated embedding vector
36
-
37
- **`@param`** [Hash] Flexible metadata for the node (default: {})
38
-
39
- **`@return`** [Hash] { node_id:, is_new:, robot_node: }
40
-
41
- ## add_tag(node_id:, tag:) {: #method-i-add_tag }
42
- Add a tag to a node
43
-
44
- **`@param`** [Integer] Node database ID
45
-
46
- **`@param`** [String] Tag name
47
-
48
- **`@return`** [void]
49
-
50
- ## batch_load_node_tags(node_ids) {: #method-i-batch_load_node_tags }
51
- Batch load tags for multiple nodes (avoids N+1 queries)
52
-
53
- **`@param`** [Array<Integer>] Node database IDs
54
-
55
- **`@return`** [Hash<Integer, Array<String>>] Map of node_id to array of tag names
56
-
57
- ## calculate_relevance(node:, query_tags:[], vector_similarity:nil, node_tags:nil) {: #method-i-calculate_relevance }
58
- Calculate dynamic relevance score for a node given query context
59
-
60
- Combines multiple signals:
61
- * Vector similarity (semantic match)
62
- * Tag overlap (categorical match)
63
- * Recency (freshness)
64
- * Access frequency (popularity/utility)
65
-
66
- **`@param`** [Hash] Node data with similarity, tags, created_at, access_count
67
-
68
- **`@param`** [Array<String>] Tags associated with the query
69
-
70
- **`@param`** [Float, nil] Pre-computed vector similarity (0-1)
71
-
72
- **`@param`** [Array<String>, nil] Pre-loaded tags for this node (avoids N+1 query)
73
-
74
- **`@return`** [Float] Composite relevance score (0-10)
75
-
76
40
  ## clear_cache!() {: #method-i-clear_cache! }
77
- Clear the query cache
78
-
79
- Call this after any operation that modifies data (soft delete, restore, etc.)
80
- to ensure subsequent queries see fresh results.
81
-
82
- **`@return`** [void]
83
-
84
- ## delete(node_id) {: #method-i-delete }
85
- Delete a node
86
-
87
- **`@param`** [Integer] Node database ID
41
+ Clear the query result cache
88
42
 
89
43
  **`@return`** [void]
90
44
 
91
- ## exists?(node_id) {: #method-i-exists? }
92
- Check if a node exists
93
-
94
- **`@param`** [Integer] Node database ID
95
-
96
- **`@return`** [Boolean] True if node exists
97
-
98
- ## find_query_matching_tags(query, include_extracted:false) {: #method-i-find_query_matching_tags }
99
- Find tags that match terms in the query
100
-
101
- Searches the tags table for tags where any hierarchy level matches query
102
- words. For example, query "PostgreSQL database" would match tags like
103
- "database:postgresql", "database:sql", etc. Find tags matching a query using
104
- semantic extraction
105
-
106
- **`@param`** [String] Search query
107
-
108
- **`@param`** [Boolean] If true, returns hash with :extracted and :matched keys
109
-
110
- **`@return`** [Array<String>] Matching tag names (default)
111
-
112
- **`@return`** [Hash] If include_extracted: { extracted: [...], matched: [...] }
113
-
114
- ## get_node_tags(node_id) {: #method-i-get_node_tags }
115
- Get tags for a specific node
116
-
117
- **`@param`** [Integer] Node database ID
118
-
119
- **`@return`** [Array<String>] Tag names
120
-
121
45
  ## initialize(config, pool_size:nil, query_timeout:DEFAULT_QUERY_TIMEOUT, cache_size:DEFAULT_CACHE_SIZE, cache_ttl:DEFAULT_CACHE_TTL) {: #method-i-initialize }
122
46
  Initialize long-term memory storage
123
47
 
@@ -146,160 +70,9 @@ ltm = LongTermMemory.new(config, cache_size: 500, cache_ttl: 600)
146
70
  ```ruby
147
71
  ltm = LongTermMemory.new(config, cache_size: 0)
148
72
  ```
149
- ## link_robot_to_node(robot_id:, node:, working_memory:false) {: #method-i-link_robot_to_node }
150
- Link a robot to a node (create or update robot_node record)
151
-
152
- **`@param`** [Integer] Robot ID
153
-
154
- **`@param`** [HTM::Models::Node] Node to link
155
-
156
- **`@param`** [Boolean] Whether node is in working memory (default: false)
157
-
158
- **`@return`** [HTM::Models::RobotNode] The robot_node link record
159
-
160
- ## mark_evicted(robot_id:, node_ids:) {: #method-i-mark_evicted }
161
- Mark nodes as evicted from working memory
162
-
163
- Sets working_memory = false on the robot_nodes join table for the specified
164
- robot and node IDs.
165
-
166
- **`@param`** [Integer] Robot ID whose working memory is being evicted
167
-
168
- **`@param`** [Array<Integer>] Node IDs to mark as evicted
169
-
170
- **`@return`** [void]
171
-
172
- ## node_topics(node_id) {: #method-i-node_topics }
173
- Get topics for a specific node
174
-
175
- **`@param`** [Integer] Node database ID
176
-
177
- **`@return`** [Array<String>] Topic paths
178
-
179
- ## nodes_by_topic(topic_path, exact:false, limit:50) {: #method-i-nodes_by_topic }
180
- Retrieve nodes by ontological topic
181
-
182
- **`@param`** [String] Topic hierarchy path
183
-
184
- **`@param`** [Boolean] Exact match or prefix match
185
-
186
- **`@param`** [Integer] Maximum results
187
-
188
- **`@return`** [Array<Hash>] Matching nodes
189
-
190
- ## ontology_structure() {: #method-i-ontology_structure }
191
- Get ontology structure view
192
-
193
- **`@return`** [Array<Hash>] Ontology structure
194
-
195
73
  ## pool_size() {: #method-i-pool_size }
196
74
  For backwards compatibility with tests/code that expect pool_size
197
75
 
198
- ## popular_tags(limit:20, timeframe:nil) {: #method-i-popular_tags }
199
- Get most popular tags
200
-
201
- **`@param`** [Integer] Number of tags to return
202
-
203
- **`@param`** [Range, nil] Optional time range filter
204
-
205
- **`@return`** [Array<Hash>] Tags with usage counts
206
-
207
- ## register_robot(robot_name) {: #method-i-register_robot }
208
- Register a robot
209
-
210
- **`@param`** [String] Robot identifier
211
-
212
- **`@param`** [String] Robot name
213
-
214
- **`@return`** [void]
215
-
216
- ## retrieve(node_id) {: #method-i-retrieve }
217
- Retrieve a node by ID
218
-
219
- Automatically tracks access by incrementing access_count and updating
220
- last_accessed
221
-
222
- **`@param`** [Integer] Node database ID
223
-
224
- **`@return`** [Hash, nil] Node data or nil
225
-
226
- ## search(timeframe:, query:, limit:, embedding_service:, metadata:{}) {: #method-i-search }
227
- Vector similarity search
228
-
229
- **`@param`** [nil, Range, Array<Range>] Time range(s) to search (nil = no filter)
230
-
231
- **`@param`** [String] Search query
232
-
233
- **`@param`** [Integer] Maximum results
234
-
235
- **`@param`** [Object] Service to generate embeddings
236
-
237
- **`@param`** [Hash] Filter by metadata fields (default: {})
238
-
239
- **`@return`** [Array<Hash>] Matching nodes
240
-
241
- ## search_by_tags(tags:, match_all:false, timeframe:nil, limit:20) {: #method-i-search_by_tags }
242
- Search nodes by tags
243
-
244
- **`@param`** [Array<String>] Tags to search for
245
-
246
- **`@param`** [Boolean] If true, match ALL tags; if false, match ANY tag
247
-
248
- **`@param`** [Range, nil] Optional time range filter
249
-
250
- **`@param`** [Integer] Maximum results
251
-
252
- **`@return`** [Array<Hash>] Matching nodes with relevance scores
253
-
254
- ## search_fulltext(timeframe:, query:, limit:, metadata:{}) {: #method-i-search_fulltext }
255
- Full-text search
256
-
257
- **`@param`** [Range] Time range to search
258
-
259
- **`@param`** [String] Search query
260
-
261
- **`@param`** [Integer] Maximum results
262
-
263
- **`@param`** [Hash] Filter by metadata fields (default: {})
264
-
265
- **`@return`** [Array<Hash>] Matching nodes
266
-
267
- ## search_hybrid(timeframe:, query:, limit:, embedding_service:, prefilter_limit:100, metadata:{}) {: #method-i-search_hybrid }
268
- Hybrid search (full-text + vector)
269
-
270
- **`@param`** [Range] Time range to search
271
-
272
- **`@param`** [String] Search query
273
-
274
- **`@param`** [Integer] Maximum results
275
-
276
- **`@param`** [Object] Service to generate embeddings
277
-
278
- **`@param`** [Integer] Candidates to consider (default: 100)
279
-
280
- **`@param`** [Hash] Filter by metadata fields (default: {})
281
-
282
- **`@return`** [Array<Hash>] Matching nodes
283
-
284
- ## search_with_relevance(timeframe:, query:nil, query_tags:[], limit:20, embedding_service:nil, metadata:{}) {: #method-i-search_with_relevance }
285
- Search with dynamic relevance scoring
286
-
287
- Returns nodes with calculated relevance scores based on query context
288
-
289
- **`@param`** [nil, Range, Array<Range>] Time range(s) to search (nil = no filter)
290
-
291
- **`@param`** [String, nil] Search query
292
-
293
- **`@param`** [Array<String>] Tags to match
294
-
295
- **`@param`** [Integer] Maximum results
296
-
297
- **`@param`** [Object, nil] Service to generate embeddings
298
-
299
- **`@param`** [Hash] Filter by metadata fields (default: {})
300
-
301
- **`@return`** [Array<Hash>] Nodes with relevance scores
302
-
303
76
  ## shutdown() {: #method-i-shutdown }
304
77
  Shutdown - no-op with ActiveRecord (connection pool managed by ActiveRecord)
305
78
 
@@ -308,35 +81,3 @@ Get memory statistics
308
81
 
309
82
  **`@return`** [Hash] Statistics
310
83
 
311
- ## topic_relationships(min_shared_nodes:2, limit:50) {: #method-i-topic_relationships }
312
- Get topic relationships (co-occurrence)
313
-
314
- **`@param`** [Integer] Minimum shared nodes
315
-
316
- **`@param`** [Integer] Maximum relationships
317
-
318
- **`@return`** [Array<Hash>] Topic relationships
319
-
320
- ## track_access(node_ids) {: #method-i-track_access }
321
- Track access for multiple nodes (bulk operation)
322
-
323
- Updates access_count and last_accessed for all nodes in the array
324
-
325
- **`@param`** [Array<Integer>] Node IDs that were accessed
326
-
327
- **`@return`** [void]
328
-
329
- ## update_last_accessed(node_id) {: #method-i-update_last_accessed }
330
- Update last_accessed timestamp
331
-
332
- **`@param`** [Integer] Node database ID
333
-
334
- **`@return`** [void]
335
-
336
- ## update_robot_activity(robot_id) {: #method-i-update_robot_activity }
337
- Update robot activity timestamp
338
-
339
- **`@param`** [String] Robot identifier
340
-
341
- **`@return`** [void]
342
-
@@ -0,0 +1,18 @@
1
+ # Exception: HTM::PropositionError
2
+ **Inherits:** HTM::Error
3
+
4
+
5
+ Raised when proposition extraction fails
6
+
7
+ Common causes:
8
+ * LLM provider API errors
9
+ * Invalid proposition response format
10
+ * Network connectivity issues
11
+ * Model not available
12
+
13
+ Note: This error is distinct from CircuitBreakerOpenError. PropositionError
14
+ indicates a single failure, while CircuitBreakerOpenError indicates repeated
15
+ failures have triggered protective circuit breaking.
16
+
17
+
18
+
@@ -0,0 +1,66 @@
1
+ # Class: HTM::PropositionService
2
+ **Inherits:** Object
3
+
4
+
5
+ Proposition Service - Extracts atomic factual propositions from text
6
+
7
+ This service breaks complex text into simple, self-contained factual
8
+ statements that can be stored as independent memory nodes. Each proposition:
9
+ * Expresses a single fact
10
+ * Is understandable without context
11
+ * Uses full names, not pronouns
12
+ * Includes relevant dates/qualifiers
13
+ * Contains one subject-predicate relationship
14
+
15
+ The actual LLM call is delegated to HTM.configuration.proposition_extractor
16
+
17
+
18
+ **`@example`**
19
+ ```ruby
20
+ propositions = HTM::PropositionService.extract(
21
+ "In 1969, Neil Armstrong became the first person to walk on the Moon during Apollo 11."
22
+ )
23
+ # => ["Neil Armstrong was an astronaut.",
24
+ # "Neil Armstrong walked on the Moon in 1969.",
25
+ # "Neil Armstrong was the first person to walk on the Moon.",
26
+ # "Neil Armstrong walked on the Moon during the Apollo 11 mission.",
27
+ # "The Apollo 11 mission occurred in 1969."]
28
+ ```
29
+ # Class Methods
30
+ ## circuit_breaker() {: #method-c-circuit_breaker }
31
+ Get or create the circuit breaker for proposition service
32
+ **`@return`** [HTM::CircuitBreaker] The circuit breaker instance
33
+
34
+ ## extract(content ) {: #method-c-extract }
35
+ Extract propositions from text content
36
+ **`@param`** [String] Text to analyze
37
+
38
+ **`@raise`** [CircuitBreakerOpenError] If circuit breaker is open
39
+
40
+ **`@raise`** [PropositionError] If extraction fails
41
+
42
+ **`@return`** [Array<String>] Array of atomic propositions
43
+
44
+ ## parse_propositions(raw_propositions ) {: #method-c-parse_propositions }
45
+ Parse proposition response (handles string or array input)
46
+ **`@param`** [String, Array] Raw response from extractor
47
+
48
+ **`@return`** [Array<String>] Parsed proposition strings
49
+
50
+ ## reset_circuit_breaker!() {: #method-c-reset_circuit_breaker! }
51
+ Reset the circuit breaker (useful for testing)
52
+ **`@return`** [void]
53
+
54
+ ## valid_proposition?(proposition ) {: #method-c-valid_proposition? }
55
+ Validate single proposition
56
+ **`@param`** [String] Proposition to validate
57
+
58
+ **`@return`** [Boolean] True if valid
59
+
60
+ ## validate_and_filter_propositions(propositions ) {: #method-c-validate_and_filter_propositions }
61
+ Validate and filter propositions
62
+ **`@param`** [Array<String>] Parsed propositions
63
+
64
+ **`@return`** [Array<String>] Valid propositions only
65
+
66
+
@@ -0,0 +1,88 @@
1
+ # Class: HTM::QueryCache
2
+ **Inherits:** Object
3
+
4
+
5
+ Thread-safe query result cache with TTL and statistics
6
+
7
+ Provides LRU caching for expensive query results with:
8
+ * Configurable size and TTL
9
+ * Thread-safe statistics tracking
10
+ * Fast cache key generation (using Ruby's built-in hash)
11
+ * Selective cache invalidation by method type
12
+
13
+
14
+ **`@example`**
15
+ ```ruby
16
+ cache = HTM::QueryCache.new(size: 1000, ttl: 300)
17
+ ```
18
+ **`@example`**
19
+ ```ruby
20
+ result = cache.fetch(:search, timeframe, query, limit) do
21
+ expensive_search_operation
22
+ end
23
+ ```
24
+ **`@example`**
25
+ ```ruby
26
+ cache.stats
27
+ # => { hits: 42, misses: 10, hit_rate: 80.77, size: 52 }
28
+ ```
29
+ **`@example`**
30
+ ```ruby
31
+ cache.invalidate_methods!(:search, :hybrid) # Only invalidate search-related entries
32
+ ```
33
+ # Attributes
34
+ ## enabled[RW] {: #attribute-i-enabled }
35
+ Returns the value of attribute enabled.
36
+
37
+
38
+ # Instance Methods
39
+ ## clear!() {: #method-i-clear! }
40
+ Clear all cached entries
41
+
42
+ **`@return`** [void]
43
+
44
+ ## enabled?() {: #method-i-enabled? }
45
+ Check if cache is enabled
46
+
47
+ **`@return`** [Boolean]
48
+
49
+ ## fetch(method, *args, &block) {: #method-i-fetch }
50
+ Fetch a value from cache or execute block
51
+
52
+ **`@param`** [Symbol] Method name for cache key
53
+
54
+ **`@param`** [Array] Arguments for cache key
55
+
56
+ **`@return`** [Object] Cached or computed value
57
+
58
+ **`@yield`** [] Block that computes the value if not cached
59
+
60
+ ## initialize(size:1000, ttl:300) {: #method-i-initialize }
61
+ Initialize a new query cache
62
+
63
+ **`@param`** [Integer] Maximum number of entries (default: 1000, use 0 to disable)
64
+
65
+ **`@param`** [Integer] Time-to-live in seconds (default: 300)
66
+
67
+ **`@return`** [QueryCache] a new instance of QueryCache
68
+
69
+ ## invalidate!() {: #method-i-invalidate! }
70
+ Invalidate cache (alias for clear!)
71
+
72
+ **`@return`** [void]
73
+
74
+ ## invalidate_methods!(*methods) {: #method-i-invalidate_methods! }
75
+ Invalidate cache entries for specific methods only
76
+
77
+ More efficient than full invalidation when only certain types of cached data
78
+ need to be refreshed.
79
+
80
+ **`@param`** [Array<Symbol>] Method names to invalidate
81
+
82
+ **`@return`** [Integer] Number of entries invalidated
83
+
84
+ ## stats() {: #method-i-stats }
85
+ Get cache statistics
86
+
87
+ **`@return`** [Hash, nil] Statistics hash or nil if disabled
88
+