htm 0.0.30 → 0.0.32

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 (161) hide show
  1. checksums.yaml +4 -4
  2. data/.irbrc +2 -3
  3. data/.rubocop.yml +184 -0
  4. data/CHANGELOG.md +46 -0
  5. data/README.md +2 -0
  6. data/Rakefile +93 -12
  7. data/db/migrate/00008_create_node_relationships.rb +54 -0
  8. data/db/migrate/00009_fix_node_relationships_column_types.rb +17 -0
  9. data/db/schema.sql +124 -1
  10. data/docs/api/database.md +35 -57
  11. data/docs/api/embedding-service.md +1 -1
  12. data/docs/api/index.md +26 -15
  13. data/docs/api/working-memory.md +8 -8
  14. data/docs/architecture/index.md +5 -7
  15. data/docs/architecture/overview.md +5 -8
  16. data/docs/assets/images/htm-architecture-overview.svg +1 -1
  17. data/docs/assets/images/htm-context-assembly-flow.svg +2 -2
  18. data/docs/assets/images/htm-layered-architecture.svg +3 -3
  19. data/docs/assets/images/two-tier-memory-architecture.svg +1 -1
  20. data/docs/database/README.md +1 -0
  21. data/docs/database_rake_tasks.md +20 -28
  22. data/docs/development/contributing.md +5 -5
  23. data/docs/development/index.md +4 -7
  24. data/docs/development/schema.md +71 -1
  25. data/docs/development/setup.md +40 -82
  26. data/docs/development/testing.md +1 -1
  27. data/docs/examples/file-loading.md +4 -4
  28. data/docs/examples/mcp-client.md +1 -1
  29. data/docs/getting-started/quick-start.md +4 -4
  30. data/docs/guides/adding-memories.md +14 -1
  31. data/docs/guides/configuration.md +5 -5
  32. data/docs/guides/context-assembly.md +4 -4
  33. data/docs/guides/file-loading.md +12 -12
  34. data/docs/guides/getting-started.md +2 -2
  35. data/docs/guides/long-term-memory.md +7 -27
  36. data/docs/guides/propositions.md +20 -19
  37. data/docs/guides/recalling-memories.md +5 -5
  38. data/docs/guides/tags.md +18 -13
  39. data/docs/multi_framework_support.md +1 -1
  40. data/docs/robots/hive-mind.md +1 -1
  41. data/docs/robots/multi-robot.md +2 -2
  42. data/docs/robots/robot-groups.md +1 -1
  43. data/docs/robots/two-tier-memory.md +72 -94
  44. data/docs/setup_local_database.md +8 -54
  45. data/docs/using_rake_tasks_in_your_app.md +6 -6
  46. data/examples/01_basic_usage.rb +1 -0
  47. data/examples/03_custom_llm_configuration.rb +1 -0
  48. data/examples/04_file_loader_usage.rb +1 -0
  49. data/examples/05_timeframe_demo.rb +1 -0
  50. data/examples/06_example_app/app.rb +1 -0
  51. data/examples/07_cli_app/htm_cli.rb +1 -0
  52. data/examples/09_mcp_client.rb +1 -0
  53. data/examples/10_telemetry/demo.rb +1 -0
  54. data/examples/11_robot_groups/multi_process.rb +1 -0
  55. data/examples/11_robot_groups/same_process.rb +1 -0
  56. data/examples/12_rails_app/.envrc +12 -0
  57. data/examples/12_rails_app/Gemfile +8 -3
  58. data/examples/12_rails_app/Gemfile.lock +94 -89
  59. data/examples/12_rails_app/README.md +70 -19
  60. data/examples/12_rails_app/app/controllers/application_controller.rb +6 -0
  61. data/examples/12_rails_app/app/controllers/chats_controller.rb +305 -0
  62. data/examples/12_rails_app/app/controllers/dashboard_controller.rb +3 -0
  63. data/examples/12_rails_app/app/controllers/files_controller.rb +17 -2
  64. data/examples/12_rails_app/app/controllers/home_controller.rb +8 -0
  65. data/examples/12_rails_app/app/controllers/memories_controller.rb +9 -4
  66. data/examples/12_rails_app/app/controllers/messages_controller.rb +214 -0
  67. data/examples/12_rails_app/app/controllers/robots_controller.rb +11 -1
  68. data/examples/12_rails_app/app/controllers/tags_controller.rb +14 -1
  69. data/examples/12_rails_app/app/javascript/application.js +1 -1
  70. data/examples/12_rails_app/app/models/application_record.rb +5 -0
  71. data/examples/12_rails_app/app/models/chat.rb +36 -0
  72. data/examples/12_rails_app/app/models/message.rb +5 -0
  73. data/examples/12_rails_app/app/models/model.rb +5 -0
  74. data/examples/12_rails_app/app/models/tool_call.rb +5 -0
  75. data/examples/12_rails_app/app/views/chats/index.html.erb +61 -0
  76. data/examples/12_rails_app/app/views/chats/show.html.erb +213 -0
  77. data/examples/12_rails_app/app/views/dashboard/index.html.erb +3 -0
  78. data/examples/12_rails_app/app/views/files/index.html.erb +10 -5
  79. data/examples/12_rails_app/app/views/files/new.html.erb +4 -2
  80. data/examples/12_rails_app/app/views/files/show.html.erb +19 -3
  81. data/examples/12_rails_app/app/views/home/index.html.erb +45 -0
  82. data/examples/12_rails_app/app/views/layouts/application.html.erb +20 -18
  83. data/examples/12_rails_app/app/views/memories/_memory_card.html.erb +1 -1
  84. data/examples/12_rails_app/app/views/memories/deleted.html.erb +3 -1
  85. data/examples/12_rails_app/app/views/memories/edit.html.erb +2 -0
  86. data/examples/12_rails_app/app/views/memories/index.html.erb +2 -0
  87. data/examples/12_rails_app/app/views/memories/new.html.erb +2 -0
  88. data/examples/12_rails_app/app/views/memories/show.html.erb +4 -2
  89. data/examples/12_rails_app/app/views/messages/_message.html.erb +20 -0
  90. data/examples/12_rails_app/app/views/robots/index.html.erb +2 -0
  91. data/examples/12_rails_app/app/views/robots/new.html.erb +2 -0
  92. data/examples/12_rails_app/app/views/robots/show.html.erb +2 -0
  93. data/examples/12_rails_app/app/views/search/index.html.erb +59 -8
  94. data/examples/12_rails_app/app/views/shared/_navbar.html.erb +75 -29
  95. data/examples/12_rails_app/app/views/tags/index.html.erb +2 -0
  96. data/examples/12_rails_app/app/views/tags/show.html.erb +3 -1
  97. data/examples/12_rails_app/config/application.rb +1 -1
  98. data/examples/12_rails_app/config/database.yml +9 -5
  99. data/examples/12_rails_app/config/importmap.rb +1 -1
  100. data/examples/12_rails_app/config/initializers/htm.rb +9 -2
  101. data/examples/12_rails_app/config/initializers/ruby_llm.rb +33 -0
  102. data/examples/12_rails_app/config/routes.rb +39 -23
  103. data/examples/12_rails_app/db/migrate/20250124000001_create_ruby_llm_tables.rb +34 -0
  104. data/examples/12_rails_app/db/migrate/20250124000002_create_models_table.rb +28 -0
  105. data/examples/12_rails_app/db/schema.rb +67 -0
  106. data/examples/examples_helper.rb +25 -0
  107. data/lib/htm/circuit_breaker.rb +5 -6
  108. data/lib/htm/config/builder.rb +12 -12
  109. data/lib/htm/config/database.rb +21 -27
  110. data/lib/htm/config/defaults.yml +25 -13
  111. data/lib/htm/config/validator.rb +12 -18
  112. data/lib/htm/config.rb +93 -173
  113. data/lib/htm/database.rb +193 -199
  114. data/lib/htm/embedding_service.rb +4 -9
  115. data/lib/htm/integrations/sinatra.rb +7 -7
  116. data/lib/htm/job_adapter.rb +14 -21
  117. data/lib/htm/jobs/generate_embedding_job.rb +28 -44
  118. data/lib/htm/jobs/generate_propositions_job.rb +29 -55
  119. data/lib/htm/jobs/generate_relationships_job.rb +137 -0
  120. data/lib/htm/jobs/generate_tags_job.rb +45 -67
  121. data/lib/htm/loaders/markdown_loader.rb +65 -112
  122. data/lib/htm/long_term_memory/fulltext_search.rb +1 -1
  123. data/lib/htm/long_term_memory/hybrid_search.rb +300 -128
  124. data/lib/htm/long_term_memory/node_operations.rb +2 -2
  125. data/lib/htm/long_term_memory/relevance_scorer.rb +100 -68
  126. data/lib/htm/long_term_memory/tag_operations.rb +87 -120
  127. data/lib/htm/long_term_memory/vector_search.rb +1 -1
  128. data/lib/htm/long_term_memory.rb +2 -1
  129. data/lib/htm/mcp/cli.rb +59 -58
  130. data/lib/htm/mcp/server.rb +5 -6
  131. data/lib/htm/mcp/tools.rb +30 -36
  132. data/lib/htm/migration.rb +10 -10
  133. data/lib/htm/models/node.rb +2 -3
  134. data/lib/htm/models/node_relationship.rb +72 -0
  135. data/lib/htm/models/node_tag.rb +2 -2
  136. data/lib/htm/models/robot_node.rb +2 -2
  137. data/lib/htm/models/tag.rb +41 -28
  138. data/lib/htm/observability.rb +45 -51
  139. data/lib/htm/proposition_service.rb +3 -7
  140. data/lib/htm/query_cache.rb +13 -15
  141. data/lib/htm/railtie.rb +1 -2
  142. data/lib/htm/robot_group.rb +9 -9
  143. data/lib/htm/sequel_config.rb +1 -0
  144. data/lib/htm/sql_builder.rb +1 -1
  145. data/lib/htm/tag_service.rb +2 -6
  146. data/lib/htm/timeframe.rb +4 -5
  147. data/lib/htm/timeframe_extractor.rb +42 -83
  148. data/lib/htm/version.rb +1 -1
  149. data/lib/htm/workflows/remember_workflow.rb +112 -115
  150. data/lib/htm/working_memory.rb +21 -26
  151. data/lib/htm.rb +103 -116
  152. data/lib/tasks/db.rake +0 -2
  153. data/lib/tasks/doc.rake +14 -13
  154. data/lib/tasks/files.rake +5 -12
  155. data/lib/tasks/htm.rake +70 -71
  156. data/lib/tasks/jobs.rake +41 -47
  157. data/lib/tasks/tags.rake +3 -8
  158. metadata +28 -106
  159. data/lib/htm/config/section.rb +0 -74
  160. data/lib/htm/loaders/defaults_loader.rb +0 -166
  161. data/lib/htm/loaders/xdg_config_loader.rb +0 -116
data/lib/tasks/jobs.rake CHANGED
@@ -3,8 +3,7 @@
3
3
  namespace :htm do
4
4
  namespace :jobs do
5
5
  desc "Show statistics for nodes and async job processing"
6
- task :stats => :environment do
7
-
6
+ task stats: :environment do
8
7
  # Establish connection
9
8
  HTM::SequelConfig.establish_connection!
10
9
 
@@ -25,9 +24,9 @@ namespace :htm do
25
24
 
26
25
  # Nodes with tags
27
26
  nodes_with_tags = HTM::Models::Node
28
- .join(:node_tags, node_id: :id)
29
- .distinct
30
- .count
27
+ .join(:node_tags, node_id: :id)
28
+ .distinct
29
+ .count
31
30
  puts "Nodes with tags: #{nodes_with_tags} (#{percentage(nodes_with_tags, total_nodes)}%)"
32
31
 
33
32
  # Nodes without tags
@@ -39,7 +38,7 @@ namespace :htm do
39
38
  puts "\nTotal tags in ontology: #{total_tags}"
40
39
 
41
40
  # Tags by depth
42
- if total_tags > 0
41
+ if total_tags.positive?
43
42
  puts "\nTag hierarchy breakdown:"
44
43
  depth_counts = Hash.new(0)
45
44
  HTM::Models::Tag.select_map(:name).each do |name|
@@ -52,7 +51,7 @@ namespace :htm do
52
51
  end
53
52
 
54
53
  # Average tags per node
55
- if nodes_with_tags > 0
54
+ if nodes_with_tags.positive?
56
55
  avg_tags = HTM::Models::NodeTag.count.to_f / nodes_with_tags
57
56
  puts "\nAverage tags per node: #{avg_tags.round(2)}"
58
57
  end
@@ -61,7 +60,7 @@ namespace :htm do
61
60
  end
62
61
 
63
62
  desc "Process pending embedding jobs for nodes without embeddings"
64
- task :process_embeddings => :environment do
63
+ task process_embeddings: :environment do
65
64
  require 'ruby-progressbar'
66
65
 
67
66
  # Establish connection and configure HTM
@@ -116,7 +115,7 @@ namespace :htm do
116
115
  end
117
116
 
118
117
  desc "Process pending tag extraction jobs for nodes without tags"
119
- task :process_tags => :environment do
118
+ task process_tags: :environment do
120
119
  require 'ruby-progressbar'
121
120
 
122
121
  # Establish connection and configure HTM
@@ -125,9 +124,9 @@ namespace :htm do
125
124
 
126
125
  # Find nodes without any tags (using NOT EXISTS subquery)
127
126
  nodes_without_tags = HTM::Models::Node
128
- .where(Sequel.~(Sequel.exists(
129
- HTM::Models::NodeTag.where(Sequel[:node_tags][:node_id] => Sequel[:nodes][:id]).select(1)
130
- )))
127
+ .where(Sequel.~(Sequel.exists(
128
+ HTM::Models::NodeTag.where(Sequel[:node_tags][:node_id] => Sequel[:nodes][:id]).select(1)
129
+ )))
131
130
 
132
131
  total = nodes_without_tags.count
133
132
 
@@ -181,7 +180,7 @@ namespace :htm do
181
180
  end
182
181
 
183
182
  desc "Process pending proposition extraction for nodes without propositions"
184
- task :process_propositions => :environment do
183
+ task process_propositions: :environment do
185
184
  require 'ruby-progressbar'
186
185
 
187
186
  # Establish connection and configure HTM
@@ -193,15 +192,15 @@ namespace :htm do
193
192
  # 1. It's not a proposition itself (is_proposition != true)
194
193
  # 2. No proposition node references it as source_node_id
195
194
  processed_source_ids = HTM::Models::Node
196
- .where(Sequel.lit("metadata->>'is_proposition' = ?", 'true'))
197
- .exclude(Sequel.lit("metadata->>'source_node_id' IS NULL"))
198
- .select_map(Sequel.lit("metadata->>'source_node_id'"))
199
- .map(&:to_i)
200
- .uniq
195
+ .where(Sequel.lit("metadata->>'is_proposition' = ?", 'true'))
196
+ .exclude(Sequel.lit("metadata->>'source_node_id' IS NULL"))
197
+ .select_map(Sequel.lit("metadata->>'source_node_id'"))
198
+ .map(&:to_i)
199
+ .uniq
201
200
 
202
201
  pending_nodes = HTM::Models::Node
203
- .non_propositions
204
- .exclude(id: processed_source_ids)
202
+ .non_propositions
203
+ .exclude(id: processed_source_ids)
205
204
 
206
205
  total = pending_nodes.count
207
206
 
@@ -284,13 +283,12 @@ namespace :htm do
284
283
  end
285
284
 
286
285
  desc "Process all pending jobs (embeddings, tags, and propositions)"
287
- task :process_all => [:process_embeddings, :process_tags, :process_propositions] do
286
+ task process_all: %i[process_embeddings process_tags process_propositions] do
288
287
  puts "\nAll pending jobs processed!"
289
288
  end
290
289
 
291
290
  desc "Reprocess embeddings for all nodes (force regeneration)"
292
- task :reprocess_embeddings => :environment do
293
-
291
+ task reprocess_embeddings: :environment do
294
292
  print "This will regenerate embeddings for ALL nodes. Are you sure? (yes/no): "
295
293
  confirmation = $stdin.gets.chomp
296
294
 
@@ -311,16 +309,14 @@ namespace :htm do
311
309
  failed = 0
312
310
 
313
311
  HTM::Models::Node.paged_each do |node|
314
- begin
315
- # Use the service class directly to regenerate
316
- result = HTM::EmbeddingService.generate(node.content)
317
- node.update(embedding: result[:storage_embedding])
318
- processed += 1
319
- print "\rProcessed: #{processed}/#{total}"
320
- rescue StandardError => e
321
- failed += 1
322
- HTM.logger.error "Failed to reprocess node #{node.id}: #{e.message}"
323
- end
312
+ # Use the service class directly to regenerate
313
+ result = HTM::EmbeddingService.generate(node.content)
314
+ node.update(embedding: result[:storage_embedding])
315
+ processed += 1
316
+ print "\rProcessed: #{processed}/#{total}"
317
+ rescue StandardError => e
318
+ failed += 1
319
+ HTM.logger.error "Failed to reprocess node #{node.id}: #{e.message}"
324
320
  end
325
321
 
326
322
  puts "\n\nCompleted:"
@@ -331,8 +327,7 @@ namespace :htm do
331
327
  end
332
328
 
333
329
  desc "Show nodes that failed async processing"
334
- task :failed => :environment do
335
-
330
+ task failed: :environment do
336
331
  HTM::SequelConfig.establish_connection!
337
332
 
338
333
  puts "Nodes with Processing Issues"
@@ -340,10 +335,10 @@ namespace :htm do
340
335
 
341
336
  # Old nodes without embeddings (created more than 1 hour ago)
342
337
  old_without_embeddings = HTM::Models::Node
343
- .where(embedding: nil)
344
- .where(Sequel.lit('created_at < ?', Time.now - 3600))
338
+ .where(embedding: nil)
339
+ .where(Sequel.lit('created_at < ?', Time.now - 3600))
345
340
 
346
- if old_without_embeddings.count > 0
341
+ if old_without_embeddings.any?
347
342
  puts "\nNodes without embeddings (>1 hour old):"
348
343
  old_without_embeddings.limit(10).each do |node|
349
344
  puts " Node #{node.id}: created #{time_ago(node.created_at)}"
@@ -358,12 +353,12 @@ namespace :htm do
358
353
 
359
354
  # Old nodes without tags (using NOT EXISTS subquery)
360
355
  old_without_tags = HTM::Models::Node
361
- .where(Sequel.~(Sequel.exists(
362
- HTM::Models::NodeTag.where(Sequel[:node_tags][:node_id] => Sequel[:nodes][:id]).select(1)
363
- )))
364
- .where(Sequel.lit('created_at < ?', Time.now - 3600))
356
+ .where(Sequel.~(Sequel.exists(
357
+ HTM::Models::NodeTag.where(Sequel[:node_tags][:node_id] => Sequel[:nodes][:id]).select(1)
358
+ )))
359
+ .where(Sequel.lit('created_at < ?', Time.now - 3600))
365
360
 
366
- if old_without_tags.count > 0
361
+ if old_without_tags.any?
367
362
  puts "\nNodes without tags (>1 hour old):"
368
363
  old_without_tags.limit(10).each do |node|
369
364
  puts " Node #{node.id}: created #{time_ago(node.created_at)}"
@@ -380,8 +375,7 @@ namespace :htm do
380
375
  end
381
376
 
382
377
  desc "Clear all embeddings and tags (for testing/development)"
383
- task :clear_all => :environment do
384
-
378
+ task clear_all: :environment do
385
379
  print "This will clear ALL embeddings and tags. Are you sure? (yes/no): "
386
380
  confirmation = $stdin.gets.chomp
387
381
 
@@ -417,10 +411,10 @@ namespace :htm do
417
411
  "#{seconds.to_i} seconds ago"
418
412
  when 60..3599
419
413
  "#{(seconds / 60).to_i} minutes ago"
420
- when 3600..86399
414
+ when 3600..86_399
421
415
  "#{(seconds / 3600).to_i} hours ago"
422
416
  else
423
- "#{(seconds / 86400).to_i} days ago"
417
+ "#{(seconds / 86_400).to_i} days ago"
424
418
  end
425
419
  end
426
420
  end
data/lib/tasks/tags.rake CHANGED
@@ -12,7 +12,6 @@ namespace :htm do
12
12
  namespace :tags do
13
13
  desc "Display tags as a hierarchical tree (text format). Optional prefix filter."
14
14
  task :tree, [:prefix] do |_t, args|
15
-
16
15
  # Ensure database connection
17
16
  HTM::SequelConfig.establish_connection!
18
17
 
@@ -25,7 +24,7 @@ namespace :htm do
25
24
  end
26
25
 
27
26
  # Display tree using Tag model method
28
- puts "\nHTM Tags Tree#{args[:prefix] ? " (prefix: #{args[:prefix]})" : ''}"
27
+ puts "\nHTM Tags Tree#{" (prefix: #{args[:prefix]})" if args[:prefix]}"
29
28
  puts "=" * 40
30
29
  print tags.tree_string
31
30
  puts "\nTotal tags: #{count}"
@@ -33,7 +32,6 @@ namespace :htm do
33
32
 
34
33
  desc "Export tags as Mermaid flowchart to tags.md. Optional prefix filter."
35
34
  task :mermaid, [:prefix] do |_t, args|
36
-
37
35
  # Ensure database connection
38
36
  HTM::SequelConfig.establish_connection!
39
37
 
@@ -49,12 +47,11 @@ namespace :htm do
49
47
  File.write('tags.md', mermaid)
50
48
 
51
49
  puts "Mermaid flowchart written to: tags.md"
52
- puts "Tags exported: #{count}#{args[:prefix] ? " (prefix: #{args[:prefix]})" : ''}"
50
+ puts "Tags exported: #{count}#{" (prefix: #{args[:prefix]})" if args[:prefix]}"
53
51
  end
54
52
 
55
53
  desc "Export tags as SVG visualization to tags.svg. Optional prefix filter."
56
54
  task :svg, [:prefix] do |_t, args|
57
-
58
55
  # Ensure database connection
59
56
  HTM::SequelConfig.establish_connection!
60
57
 
@@ -71,12 +68,11 @@ namespace :htm do
71
68
  File.write('tags.svg', svg)
72
69
 
73
70
  puts "SVG visualization written to: tags.svg"
74
- puts "Tags exported: #{count}#{args[:prefix] ? " (prefix: #{args[:prefix]})" : ''}"
71
+ puts "Tags exported: #{count}#{" (prefix: #{args[:prefix]})" if args[:prefix]}"
75
72
  end
76
73
 
77
74
  desc "Rebuild all tags from node content. Clears existing tags and regenerates using LLM."
78
75
  task :rebuild do
79
-
80
76
  # Ensure database connection
81
77
  HTM::SequelConfig.establish_connection!
82
78
 
@@ -153,7 +149,6 @@ namespace :htm do
153
149
 
154
150
  desc "Export tags in all formats (tags.txt, tags.md, tags.svg). Optional prefix filter."
155
151
  task :export, [:prefix] do |_t, args|
156
-
157
152
  # Ensure database connection
158
153
  HTM::SequelConfig.establish_connection!
159
154
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: htm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.30
4
+ version: 0.0.32
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dewayne VanHoozer
@@ -150,19 +150,19 @@ dependencies:
150
150
  - !ruby/object:Gem::Version
151
151
  version: '0'
152
152
  - !ruby/object:Gem::Dependency
153
- name: anyway_config
153
+ name: myway_config
154
154
  requirement: !ruby/object:Gem::Requirement
155
155
  requirements:
156
156
  - - ">="
157
157
  - !ruby/object:Gem::Version
158
- version: '2.6'
158
+ version: 0.1.2
159
159
  type: :runtime
160
160
  prerelease: false
161
161
  version_requirements: !ruby/object:Gem::Requirement
162
162
  requirements:
163
163
  - - ">="
164
164
  - !ruby/object:Gem::Version
165
- version: '2.6'
165
+ version: 0.1.2
166
166
  - !ruby/object:Gem::Dependency
167
167
  name: simple_flow
168
168
  requirement: !ruby/object:Gem::Requirement
@@ -205,104 +205,6 @@ dependencies:
205
205
  - - ">="
206
206
  - !ruby/object:Gem::Version
207
207
  version: '0'
208
- - !ruby/object:Gem::Dependency
209
- name: rake
210
- requirement: !ruby/object:Gem::Requirement
211
- requirements:
212
- - - ">="
213
- - !ruby/object:Gem::Version
214
- version: '0'
215
- type: :development
216
- prerelease: false
217
- version_requirements: !ruby/object:Gem::Requirement
218
- requirements:
219
- - - ">="
220
- - !ruby/object:Gem::Version
221
- version: '0'
222
- - !ruby/object:Gem::Dependency
223
- name: minitest
224
- requirement: !ruby/object:Gem::Requirement
225
- requirements:
226
- - - ">="
227
- - !ruby/object:Gem::Version
228
- version: '0'
229
- type: :development
230
- prerelease: false
231
- version_requirements: !ruby/object:Gem::Requirement
232
- requirements:
233
- - - ">="
234
- - !ruby/object:Gem::Version
235
- version: '0'
236
- - !ruby/object:Gem::Dependency
237
- name: minitest-reporters
238
- requirement: !ruby/object:Gem::Requirement
239
- requirements:
240
- - - ">="
241
- - !ruby/object:Gem::Version
242
- version: '0'
243
- type: :development
244
- prerelease: false
245
- version_requirements: !ruby/object:Gem::Requirement
246
- requirements:
247
- - - ">="
248
- - !ruby/object:Gem::Version
249
- version: '0'
250
- - !ruby/object:Gem::Dependency
251
- name: debug_me
252
- requirement: !ruby/object:Gem::Requirement
253
- requirements:
254
- - - ">="
255
- - !ruby/object:Gem::Version
256
- version: '0'
257
- type: :development
258
- prerelease: false
259
- version_requirements: !ruby/object:Gem::Requirement
260
- requirements:
261
- - - ">="
262
- - !ruby/object:Gem::Version
263
- version: '0'
264
- - !ruby/object:Gem::Dependency
265
- name: ruby_llm-mcp
266
- requirement: !ruby/object:Gem::Requirement
267
- requirements:
268
- - - ">="
269
- - !ruby/object:Gem::Version
270
- version: '0'
271
- type: :development
272
- prerelease: false
273
- version_requirements: !ruby/object:Gem::Requirement
274
- requirements:
275
- - - ">="
276
- - !ruby/object:Gem::Version
277
- version: '0'
278
- - !ruby/object:Gem::Dependency
279
- name: yard
280
- requirement: !ruby/object:Gem::Requirement
281
- requirements:
282
- - - ">="
283
- - !ruby/object:Gem::Version
284
- version: '0'
285
- type: :development
286
- prerelease: false
287
- version_requirements: !ruby/object:Gem::Requirement
288
- requirements:
289
- - - ">="
290
- - !ruby/object:Gem::Version
291
- version: '0'
292
- - !ruby/object:Gem::Dependency
293
- name: yard-markdown
294
- requirement: !ruby/object:Gem::Requirement
295
- requirements:
296
- - - ">="
297
- - !ruby/object:Gem::Version
298
- version: '0'
299
- type: :development
300
- prerelease: false
301
- version_requirements: !ruby/object:Gem::Requirement
302
- requirements:
303
- - - ">="
304
- - !ruby/object:Gem::Version
305
- version: '0'
306
208
  description: |
307
209
  HTM (Hierarchical Temporal Memory) provides intelligent memory/context management for
308
210
  LLM-based applications. It implements a two-tier memory system with
@@ -339,6 +241,7 @@ files:
339
241
  - ".dictate.toml"
340
242
  - ".envrc"
341
243
  - ".irbrc"
244
+ - ".rubocop.yml"
342
245
  - ".tbls.yml"
343
246
  - CHANGELOG.md
344
247
  - COMMITS.md
@@ -354,6 +257,8 @@ files:
354
257
  - db/migrate/00005_create_tags.rb
355
258
  - db/migrate/00006_create_node_tags.rb
356
259
  - db/migrate/00007_create_robot_nodes.rb
260
+ - db/migrate/00008_create_node_relationships.rb
261
+ - db/migrate/00009_fix_node_relationships_column_types.rb
357
262
  - db/schema.sql
358
263
  - db/seed_data/README.md
359
264
  - db/seed_data/presidents.md
@@ -557,6 +462,7 @@ files:
557
462
  - examples/11_robot_groups/lib/robot_worker.rb
558
463
  - examples/11_robot_groups/multi_process.rb
559
464
  - examples/11_robot_groups/same_process.rb
465
+ - examples/12_rails_app/.envrc
560
466
  - examples/12_rails_app/.gitignore
561
467
  - examples/12_rails_app/Gemfile
562
468
  - examples/12_rails_app/Gemfile.lock
@@ -566,19 +472,30 @@ files:
566
472
  - examples/12_rails_app/app/assets/stylesheets/application.css
567
473
  - examples/12_rails_app/app/assets/stylesheets/inter-font.css
568
474
  - examples/12_rails_app/app/controllers/application_controller.rb
475
+ - examples/12_rails_app/app/controllers/chats_controller.rb
569
476
  - examples/12_rails_app/app/controllers/dashboard_controller.rb
570
477
  - examples/12_rails_app/app/controllers/files_controller.rb
478
+ - examples/12_rails_app/app/controllers/home_controller.rb
571
479
  - examples/12_rails_app/app/controllers/memories_controller.rb
480
+ - examples/12_rails_app/app/controllers/messages_controller.rb
572
481
  - examples/12_rails_app/app/controllers/robots_controller.rb
573
482
  - examples/12_rails_app/app/controllers/search_controller.rb
574
483
  - examples/12_rails_app/app/controllers/tags_controller.rb
575
484
  - examples/12_rails_app/app/javascript/application.js
576
485
  - examples/12_rails_app/app/javascript/controllers/application.js
577
486
  - examples/12_rails_app/app/javascript/controllers/index.js
487
+ - examples/12_rails_app/app/models/application_record.rb
488
+ - examples/12_rails_app/app/models/chat.rb
489
+ - examples/12_rails_app/app/models/message.rb
490
+ - examples/12_rails_app/app/models/model.rb
491
+ - examples/12_rails_app/app/models/tool_call.rb
492
+ - examples/12_rails_app/app/views/chats/index.html.erb
493
+ - examples/12_rails_app/app/views/chats/show.html.erb
578
494
  - examples/12_rails_app/app/views/dashboard/index.html.erb
579
495
  - examples/12_rails_app/app/views/files/index.html.erb
580
496
  - examples/12_rails_app/app/views/files/new.html.erb
581
497
  - examples/12_rails_app/app/views/files/show.html.erb
498
+ - examples/12_rails_app/app/views/home/index.html.erb
582
499
  - examples/12_rails_app/app/views/layouts/application.html.erb
583
500
  - examples/12_rails_app/app/views/memories/_memory_card.html.erb
584
501
  - examples/12_rails_app/app/views/memories/deleted.html.erb
@@ -586,6 +503,7 @@ files:
586
503
  - examples/12_rails_app/app/views/memories/index.html.erb
587
504
  - examples/12_rails_app/app/views/memories/new.html.erb
588
505
  - examples/12_rails_app/app/views/memories/show.html.erb
506
+ - examples/12_rails_app/app/views/messages/_message.html.erb
589
507
  - examples/12_rails_app/app/views/robots/index.html.erb
590
508
  - examples/12_rails_app/app/views/robots/new.html.erb
591
509
  - examples/12_rails_app/app/views/robots/show.html.erb
@@ -605,8 +523,12 @@ files:
605
523
  - examples/12_rails_app/config/importmap.rb
606
524
  - examples/12_rails_app/config/initializers/htm.rb
607
525
  - examples/12_rails_app/config/initializers/rack.rb
526
+ - examples/12_rails_app/config/initializers/ruby_llm.rb
608
527
  - examples/12_rails_app/config/routes.rb
609
528
  - examples/12_rails_app/config/tailwind.config.js
529
+ - examples/12_rails_app/db/migrate/20250124000001_create_ruby_llm_tables.rb
530
+ - examples/12_rails_app/db/migrate/20250124000002_create_models_table.rb
531
+ - examples/12_rails_app/db/schema.rb
610
532
  - examples/12_rails_app/log/.keep
611
533
  - examples/12_rails_app/tmp/local_secret.txt
612
534
  - examples/README.md
@@ -617,7 +539,6 @@ files:
617
539
  - lib/htm/config/builder.rb
618
540
  - lib/htm/config/database.rb
619
541
  - lib/htm/config/defaults.yml
620
- - lib/htm/config/section.rb
621
542
  - lib/htm/config/validator.rb
622
543
  - lib/htm/database.rb
623
544
  - lib/htm/embedding_service.rb
@@ -626,11 +547,10 @@ files:
626
547
  - lib/htm/job_adapter.rb
627
548
  - lib/htm/jobs/generate_embedding_job.rb
628
549
  - lib/htm/jobs/generate_propositions_job.rb
550
+ - lib/htm/jobs/generate_relationships_job.rb
629
551
  - lib/htm/jobs/generate_tags_job.rb
630
- - lib/htm/loaders/defaults_loader.rb
631
552
  - lib/htm/loaders/markdown_chunker.rb
632
553
  - lib/htm/loaders/markdown_loader.rb
633
- - lib/htm/loaders/xdg_config_loader.rb
634
554
  - lib/htm/long_term_memory.rb
635
555
  - lib/htm/long_term_memory/fulltext_search.rb
636
556
  - lib/htm/long_term_memory/hybrid_search.rb
@@ -647,6 +567,7 @@ files:
647
567
  - lib/htm/migration.rb
648
568
  - lib/htm/models/file_source.rb
649
569
  - lib/htm/models/node.rb
570
+ - lib/htm/models/node_relationship.rb
650
571
  - lib/htm/models/node_tag.rb
651
572
  - lib/htm/models/robot.rb
652
573
  - lib/htm/models/robot_node.rb
@@ -684,6 +605,7 @@ metadata:
684
605
  homepage_uri: https://github.com/madbomber/htm
685
606
  source_code_uri: https://github.com/madbomber/htm
686
607
  changelog_uri: https://github.com/madbomber/htm/blob/main/CHANGELOG.md
608
+ rubygems_mfa_required: 'true'
687
609
  rdoc_options: []
688
610
  require_paths:
689
611
  - lib
@@ -698,7 +620,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
698
620
  - !ruby/object:Gem::Version
699
621
  version: '0'
700
622
  requirements: []
701
- rubygems_version: 4.0.4
623
+ rubygems_version: 4.0.12
702
624
  specification_version: 4
703
625
  summary: Hierarchical Temporal Memory for LLM robots
704
626
  test_files: []
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class HTM
4
- # ConfigSection provides method access to nested configuration hashes
5
- #
6
- # @example
7
- # section = ConfigSection.new(host: 'localhost', port: 5432)
8
- # section.host # => 'localhost'
9
- # section.port # => 5432
10
- #
11
- class ConfigSection
12
- def initialize(hash = {})
13
- @data = {}
14
- (hash || {}).each do |key, value|
15
- @data[key.to_sym] = value.is_a?(Hash) ? ConfigSection.new(value) : value
16
- end
17
- end
18
-
19
- def method_missing(method, *args, &block)
20
- key = method.to_s
21
- if key.end_with?('=')
22
- @data[key.chomp('=').to_sym] = args.first
23
- elsif @data.key?(method)
24
- @data[method]
25
- else
26
- nil
27
- end
28
- end
29
-
30
- def respond_to_missing?(method, include_private = false)
31
- key = method.to_s.chomp('=').to_sym
32
- @data.key?(key) || super
33
- end
34
-
35
- def to_h
36
- @data.transform_values do |v|
37
- v.is_a?(ConfigSection) ? v.to_h : v
38
- end
39
- end
40
-
41
- def [](key)
42
- @data[key.to_sym]
43
- end
44
-
45
- def []=(key, value)
46
- @data[key.to_sym] = value
47
- end
48
-
49
- def merge(other)
50
- other_hash = other.is_a?(ConfigSection) ? other.to_h : other
51
- ConfigSection.new(deep_merge(to_h, other_hash || {}))
52
- end
53
-
54
- def keys
55
- @data.keys
56
- end
57
-
58
- def each(&block)
59
- @data.each(&block)
60
- end
61
-
62
- private
63
-
64
- def deep_merge(base, overlay)
65
- base.merge(overlay) do |_key, old_val, new_val|
66
- if old_val.is_a?(Hash) && new_val.is_a?(Hash)
67
- deep_merge(old_val, new_val)
68
- else
69
- new_val
70
- end
71
- end
72
- end
73
- end
74
- end