htm 0.0.2 → 0.0.11

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 (129) hide show
  1. checksums.yaml +4 -4
  2. data/.aigcm_msg +1 -0
  3. data/.architecture/reviews/comprehensive-codebase-review.md +577 -0
  4. data/.claude/settings.local.json +95 -0
  5. data/.irbrc +283 -80
  6. data/.tbls.yml +2 -1
  7. data/CHANGELOG.md +327 -26
  8. data/CLAUDE.md +603 -0
  9. data/README.md +83 -12
  10. data/Rakefile +5 -0
  11. data/bin/htm_mcp.rb +527 -0
  12. data/db/migrate/{20250101000001_enable_extensions.rb → 00001_enable_extensions.rb} +0 -1
  13. data/db/migrate/00002_create_robots.rb +11 -0
  14. data/db/migrate/00003_create_file_sources.rb +20 -0
  15. data/db/migrate/00004_create_nodes.rb +65 -0
  16. data/db/migrate/00005_create_tags.rb +13 -0
  17. data/db/migrate/00006_create_node_tags.rb +18 -0
  18. data/db/migrate/00007_create_robot_nodes.rb +26 -0
  19. data/db/migrate/00009_add_working_memory_to_robot_nodes.rb +12 -0
  20. data/db/schema.sql +172 -1
  21. data/docs/api/database.md +1 -2
  22. data/docs/api/htm.md +197 -2
  23. data/docs/api/yard/HTM/ActiveRecordConfig.md +23 -0
  24. data/docs/api/yard/HTM/AuthorizationError.md +11 -0
  25. data/docs/api/yard/HTM/CircuitBreaker.md +92 -0
  26. data/docs/api/yard/HTM/CircuitBreakerOpenError.md +34 -0
  27. data/docs/api/yard/HTM/Configuration.md +175 -0
  28. data/docs/api/yard/HTM/Database.md +99 -0
  29. data/docs/api/yard/HTM/DatabaseError.md +14 -0
  30. data/docs/api/yard/HTM/EmbeddingError.md +18 -0
  31. data/docs/api/yard/HTM/EmbeddingService.md +58 -0
  32. data/docs/api/yard/HTM/Error.md +11 -0
  33. data/docs/api/yard/HTM/JobAdapter.md +39 -0
  34. data/docs/api/yard/HTM/LongTermMemory.md +342 -0
  35. data/docs/api/yard/HTM/NotFoundError.md +17 -0
  36. data/docs/api/yard/HTM/Observability.md +107 -0
  37. data/docs/api/yard/HTM/QueryTimeoutError.md +19 -0
  38. data/docs/api/yard/HTM/Railtie.md +27 -0
  39. data/docs/api/yard/HTM/ResourceExhaustedError.md +13 -0
  40. data/docs/api/yard/HTM/TagError.md +18 -0
  41. data/docs/api/yard/HTM/TagService.md +67 -0
  42. data/docs/api/yard/HTM/Timeframe/Result.md +24 -0
  43. data/docs/api/yard/HTM/Timeframe.md +40 -0
  44. data/docs/api/yard/HTM/TimeframeExtractor/Result.md +24 -0
  45. data/docs/api/yard/HTM/TimeframeExtractor.md +45 -0
  46. data/docs/api/yard/HTM/ValidationError.md +20 -0
  47. data/docs/api/yard/HTM/WorkingMemory.md +131 -0
  48. data/docs/api/yard/HTM.md +80 -0
  49. data/docs/api/yard/index.csv +179 -0
  50. data/docs/api/yard-reference.md +51 -0
  51. data/docs/database/README.md +128 -128
  52. data/docs/database/public.file_sources.md +42 -0
  53. data/docs/database/public.file_sources.svg +211 -0
  54. data/docs/database/public.node_tags.md +4 -4
  55. data/docs/database/public.node_tags.svg +212 -79
  56. data/docs/database/public.nodes.md +22 -12
  57. data/docs/database/public.nodes.svg +246 -127
  58. data/docs/database/public.robot_nodes.md +11 -9
  59. data/docs/database/public.robot_nodes.svg +220 -98
  60. data/docs/database/public.robots.md +2 -2
  61. data/docs/database/public.robots.svg +136 -81
  62. data/docs/database/public.tags.md +3 -3
  63. data/docs/database/public.tags.svg +118 -39
  64. data/docs/database/schema.json +850 -771
  65. data/docs/database/schema.svg +256 -197
  66. data/docs/development/schema.md +67 -2
  67. data/docs/guides/adding-memories.md +93 -7
  68. data/docs/guides/recalling-memories.md +36 -1
  69. data/examples/README.md +405 -0
  70. data/examples/cli_app/htm_cli.rb +65 -5
  71. data/examples/cli_app/temp.log +93 -0
  72. data/examples/file_loader_usage.rb +177 -0
  73. data/examples/mcp_client.rb +529 -0
  74. data/examples/robot_groups/lib/robot_group.rb +419 -0
  75. data/examples/robot_groups/lib/working_memory_channel.rb +140 -0
  76. data/examples/robot_groups/multi_process.rb +286 -0
  77. data/examples/robot_groups/robot_worker.rb +136 -0
  78. data/examples/robot_groups/same_process.rb +229 -0
  79. data/examples/timeframe_demo.rb +276 -0
  80. data/lib/htm/active_record_config.rb +1 -1
  81. data/lib/htm/circuit_breaker.rb +202 -0
  82. data/lib/htm/configuration.rb +59 -13
  83. data/lib/htm/database.rb +67 -36
  84. data/lib/htm/embedding_service.rb +39 -2
  85. data/lib/htm/errors.rb +131 -11
  86. data/lib/htm/jobs/generate_embedding_job.rb +5 -4
  87. data/lib/htm/jobs/generate_tags_job.rb +4 -0
  88. data/lib/htm/loaders/markdown_loader.rb +263 -0
  89. data/lib/htm/loaders/paragraph_chunker.rb +112 -0
  90. data/lib/htm/long_term_memory.rb +460 -343
  91. data/lib/htm/models/file_source.rb +99 -0
  92. data/lib/htm/models/node.rb +80 -5
  93. data/lib/htm/models/robot.rb +24 -1
  94. data/lib/htm/models/robot_node.rb +1 -0
  95. data/lib/htm/models/tag.rb +254 -4
  96. data/lib/htm/observability.rb +395 -0
  97. data/lib/htm/tag_service.rb +60 -3
  98. data/lib/htm/tasks.rb +26 -1
  99. data/lib/htm/timeframe.rb +194 -0
  100. data/lib/htm/timeframe_extractor.rb +307 -0
  101. data/lib/htm/version.rb +1 -1
  102. data/lib/htm/working_memory.rb +165 -70
  103. data/lib/htm.rb +328 -130
  104. data/lib/tasks/doc.rake +300 -0
  105. data/lib/tasks/files.rake +299 -0
  106. data/lib/tasks/htm.rake +158 -3
  107. data/lib/tasks/jobs.rake +3 -9
  108. data/lib/tasks/tags.rake +166 -6
  109. data/mkdocs.yml +36 -1
  110. data/notes/ARCHITECTURE_REVIEW.md +1167 -0
  111. data/notes/IMPLEMENTATION_SUMMARY.md +606 -0
  112. data/notes/MULTI_FRAMEWORK_IMPLEMENTATION.md +451 -0
  113. data/notes/next_steps.md +100 -0
  114. data/notes/plan.md +627 -0
  115. data/notes/tag_ontology_enhancement_ideas.md +222 -0
  116. data/notes/timescaledb_removal_summary.md +200 -0
  117. metadata +158 -17
  118. data/db/migrate/20250101000002_create_robots.rb +0 -14
  119. data/db/migrate/20250101000003_create_nodes.rb +0 -42
  120. data/db/migrate/20250101000005_create_tags.rb +0 -38
  121. data/db/migrate/20250101000007_add_node_vector_indexes.rb +0 -30
  122. data/db/migrate/20250125000001_add_content_hash_to_nodes.rb +0 -14
  123. data/db/migrate/20250125000002_create_robot_nodes.rb +0 -35
  124. data/db/migrate/20250125000003_remove_source_and_robot_id_from_nodes.rb +0 -28
  125. data/db/migrate/20250126000001_create_working_memories.rb +0 -19
  126. data/db/migrate/20250126000002_remove_unused_columns.rb +0 -12
  127. data/docs/database/public.working_memories.md +0 -40
  128. data/docs/database/public.working_memories.svg +0 -112
  129. data/lib/htm/models/working_memory_entry.rb +0 -88
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: htm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dewayne VanHoozer
8
- bindir: exe
8
+ bindir: bin
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
@@ -93,6 +93,48 @@ dependencies:
93
93
  - - ">="
94
94
  - !ruby/object:Gem::Version
95
95
  version: '0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: ruby-progressbar
98
+ requirement: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ - !ruby/object:Gem::Dependency
111
+ name: chronic
112
+ requirement: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ type: :runtime
118
+ prerelease: false
119
+ version_requirements: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ - !ruby/object:Gem::Dependency
125
+ name: fast-mcp
126
+ requirement: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ type: :runtime
132
+ prerelease: false
133
+ version_requirements: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
96
138
  - !ruby/object:Gem::Dependency
97
139
  name: rake
98
140
  requirement: !ruby/object:Gem::Requirement
@@ -149,6 +191,48 @@ dependencies:
149
191
  - - ">="
150
192
  - !ruby/object:Gem::Version
151
193
  version: '0'
194
+ - !ruby/object:Gem::Dependency
195
+ name: ruby_llm-mcp
196
+ requirement: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
201
+ type: :development
202
+ prerelease: false
203
+ version_requirements: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - ">="
206
+ - !ruby/object:Gem::Version
207
+ version: '0'
208
+ - !ruby/object:Gem::Dependency
209
+ name: yard
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: yard-markdown
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'
152
236
  description: |
153
237
  HTM (Hierarchical Temporary Memory) provides intelligent memory management for
154
238
  LLM-based applications. It implements a two-tier memory system with
@@ -157,10 +241,12 @@ description: |
157
241
  (Retrieval-Augmented Generation) techniques.
158
242
  email:
159
243
  - dvanhoozer@gmail.com
160
- executables: []
244
+ executables:
245
+ - htm_mcp.rb
161
246
  extensions: []
162
247
  extra_rdoc_files: []
163
248
  files:
249
+ - ".aigcm_msg"
164
250
  - ".architecture/decisions/adrs/001-use-postgresql-timescaledb-storage.md"
165
251
  - ".architecture/decisions/adrs/002-two-tier-memory-architecture.md"
166
252
  - ".architecture/decisions/adrs/003-ollama-default-embedding-provider.md"
@@ -179,27 +265,29 @@ files:
179
265
  - ".architecture/decisions/adrs/016-async-embedding-and-tag-generation.md"
180
266
  - ".architecture/members.yml"
181
267
  - ".architecture/reviews/2025-10-29-llm-configuration-and-async-processing-review.md"
268
+ - ".architecture/reviews/comprehensive-codebase-review.md"
182
269
  - ".architecture/reviews/initial-system-analysis.md"
270
+ - ".claude/settings.local.json"
183
271
  - ".envrc"
184
272
  - ".irbrc"
185
273
  - ".tbls.yml"
186
274
  - CHANGELOG.md
275
+ - CLAUDE.md
187
276
  - COMMITS.md
188
277
  - LICENSE
189
278
  - README.md
190
279
  - Rakefile
191
280
  - SETUP.md
281
+ - bin/htm_mcp.rb
192
282
  - config/database.yml
193
- - db/migrate/20250101000001_enable_extensions.rb
194
- - db/migrate/20250101000002_create_robots.rb
195
- - db/migrate/20250101000003_create_nodes.rb
196
- - db/migrate/20250101000005_create_tags.rb
197
- - db/migrate/20250101000007_add_node_vector_indexes.rb
198
- - db/migrate/20250125000001_add_content_hash_to_nodes.rb
199
- - db/migrate/20250125000002_create_robot_nodes.rb
200
- - db/migrate/20250125000003_remove_source_and_robot_id_from_nodes.rb
201
- - db/migrate/20250126000001_create_working_memories.rb
202
- - db/migrate/20250126000002_remove_unused_columns.rb
283
+ - db/migrate/00001_enable_extensions.rb
284
+ - db/migrate/00002_create_robots.rb
285
+ - db/migrate/00003_create_file_sources.rb
286
+ - db/migrate/00004_create_nodes.rb
287
+ - db/migrate/00005_create_tags.rb
288
+ - db/migrate/00006_create_node_tags.rb
289
+ - db/migrate/00007_create_robot_nodes.rb
290
+ - db/migrate/00009_add_working_memory_to_robot_nodes.rb
203
291
  - db/schema.sql
204
292
  - db/seed_data/README.md
205
293
  - db/seed_data/presidents.md
@@ -211,6 +299,34 @@ files:
211
299
  - docs/api/index.md
212
300
  - docs/api/long-term-memory.md
213
301
  - docs/api/working-memory.md
302
+ - docs/api/yard-reference.md
303
+ - docs/api/yard/HTM.md
304
+ - docs/api/yard/HTM/ActiveRecordConfig.md
305
+ - docs/api/yard/HTM/AuthorizationError.md
306
+ - docs/api/yard/HTM/CircuitBreaker.md
307
+ - docs/api/yard/HTM/CircuitBreakerOpenError.md
308
+ - docs/api/yard/HTM/Configuration.md
309
+ - docs/api/yard/HTM/Database.md
310
+ - docs/api/yard/HTM/DatabaseError.md
311
+ - docs/api/yard/HTM/EmbeddingError.md
312
+ - docs/api/yard/HTM/EmbeddingService.md
313
+ - docs/api/yard/HTM/Error.md
314
+ - docs/api/yard/HTM/JobAdapter.md
315
+ - docs/api/yard/HTM/LongTermMemory.md
316
+ - docs/api/yard/HTM/NotFoundError.md
317
+ - docs/api/yard/HTM/Observability.md
318
+ - docs/api/yard/HTM/QueryTimeoutError.md
319
+ - docs/api/yard/HTM/Railtie.md
320
+ - docs/api/yard/HTM/ResourceExhaustedError.md
321
+ - docs/api/yard/HTM/TagError.md
322
+ - docs/api/yard/HTM/TagService.md
323
+ - docs/api/yard/HTM/Timeframe.md
324
+ - docs/api/yard/HTM/Timeframe/Result.md
325
+ - docs/api/yard/HTM/TimeframeExtractor.md
326
+ - docs/api/yard/HTM/TimeframeExtractor/Result.md
327
+ - docs/api/yard/HTM/ValidationError.md
328
+ - docs/api/yard/HTM/WorkingMemory.md
329
+ - docs/api/yard/index.csv
214
330
  - docs/architecture/adrs/001-postgresql-timescaledb.md
215
331
  - docs/architecture/adrs/002-two-tier-memory.md
216
332
  - docs/architecture/adrs/003-ollama-embeddings.md
@@ -254,6 +370,8 @@ files:
254
370
  - docs/assets/js/mathjax.js
255
371
  - docs/assets/videos/htm_video.mp4
256
372
  - docs/database/README.md
373
+ - docs/database/public.file_sources.md
374
+ - docs/database/public.file_sources.svg
257
375
  - docs/database/public.node_stats.md
258
376
  - docs/database/public.node_stats.svg
259
377
  - docs/database/public.node_tags.md
@@ -280,8 +398,6 @@ files:
280
398
  - docs/database/public.tags.svg
281
399
  - docs/database/public.topic_relationships.md
282
400
  - docs/database/public.topic_relationships.svg
283
- - docs/database/public.working_memories.md
284
- - docs/database/public.working_memories.svg
285
401
  - docs/database/schema.json
286
402
  - docs/database/schema.svg
287
403
  - docs/database_rake_tasks.md
@@ -307,17 +423,28 @@ files:
307
423
  - docs/multi_framework_support.md
308
424
  - docs/setup_local_database.md
309
425
  - docs/using_rake_tasks_in_your_app.md
426
+ - examples/README.md
310
427
  - examples/basic_usage.rb
311
428
  - examples/cli_app/README.md
312
429
  - examples/cli_app/htm_cli.rb
430
+ - examples/cli_app/temp.log
313
431
  - examples/custom_llm_configuration.rb
314
432
  - examples/example_app/Rakefile
315
433
  - examples/example_app/app.rb
434
+ - examples/file_loader_usage.rb
435
+ - examples/mcp_client.rb
436
+ - examples/robot_groups/lib/robot_group.rb
437
+ - examples/robot_groups/lib/working_memory_channel.rb
438
+ - examples/robot_groups/multi_process.rb
439
+ - examples/robot_groups/robot_worker.rb
440
+ - examples/robot_groups/same_process.rb
316
441
  - examples/sinatra_app/Gemfile
317
442
  - examples/sinatra_app/Gemfile.lock
318
443
  - examples/sinatra_app/app.rb
444
+ - examples/timeframe_demo.rb
319
445
  - lib/htm.rb
320
446
  - lib/htm/active_record_config.rb
447
+ - lib/htm/circuit_breaker.rb
321
448
  - lib/htm/configuration.rb
322
449
  - lib/htm/database.rb
323
450
  - lib/htm/embedding_service.rb
@@ -326,23 +453,37 @@ files:
326
453
  - lib/htm/job_adapter.rb
327
454
  - lib/htm/jobs/generate_embedding_job.rb
328
455
  - lib/htm/jobs/generate_tags_job.rb
456
+ - lib/htm/loaders/markdown_loader.rb
457
+ - lib/htm/loaders/paragraph_chunker.rb
329
458
  - lib/htm/long_term_memory.rb
459
+ - lib/htm/models/file_source.rb
330
460
  - lib/htm/models/node.rb
331
461
  - lib/htm/models/node_tag.rb
332
462
  - lib/htm/models/robot.rb
333
463
  - lib/htm/models/robot_node.rb
334
464
  - lib/htm/models/tag.rb
335
- - lib/htm/models/working_memory_entry.rb
465
+ - lib/htm/observability.rb
336
466
  - lib/htm/railtie.rb
337
467
  - lib/htm/tag_service.rb
338
468
  - lib/htm/tasks.rb
469
+ - lib/htm/timeframe.rb
470
+ - lib/htm/timeframe_extractor.rb
339
471
  - lib/htm/version.rb
340
472
  - lib/htm/working_memory.rb
341
473
  - lib/tasks/db.rake
474
+ - lib/tasks/doc.rake
475
+ - lib/tasks/files.rake
342
476
  - lib/tasks/htm.rake
343
477
  - lib/tasks/jobs.rake
344
478
  - lib/tasks/tags.rake
345
479
  - mkdocs.yml
480
+ - notes/ARCHITECTURE_REVIEW.md
481
+ - notes/IMPLEMENTATION_SUMMARY.md
482
+ - notes/MULTI_FRAMEWORK_IMPLEMENTATION.md
483
+ - notes/next_steps.md
484
+ - notes/plan.md
485
+ - notes/tag_ontology_enhancement_ideas.md
486
+ - notes/timescaledb_removal_summary.md
346
487
  - scripts/install_local_database.sh
347
488
  homepage: https://github.com/madbomber/htm
348
489
  licenses:
@@ -365,7 +506,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
365
506
  - !ruby/object:Gem::Version
366
507
  version: '0'
367
508
  requirements: []
368
- rubygems_version: 3.7.2
509
+ rubygems_version: 4.0.0.dev
369
510
  specification_version: 4
370
511
  summary: Hierarchical Temporary Memory for LLM robots
371
512
  test_files: []
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateRobots < ActiveRecord::Migration[7.1]
4
- def change
5
- unless table_exists?(:robots)
6
- create_table :robots, comment: 'Registry of all LLM robots using the HTM system' do |t|
7
- t.text :name, comment: 'Human-readable name for the robot'
8
- t.timestamptz :created_at, default: -> { 'CURRENT_TIMESTAMP' }, comment: 'When the robot was first registered'
9
- t.timestamptz :last_active, default: -> { 'CURRENT_TIMESTAMP' }, comment: 'Last time the robot accessed the system'
10
- t.jsonb :metadata, comment: 'Robot-specific configuration and metadata'
11
- end
12
- end
13
- end
14
- end
@@ -1,42 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateNodes < ActiveRecord::Migration[7.1]
4
- def change
5
- unless table_exists?(:nodes)
6
- create_table :nodes, comment: 'Core memory storage for conversation messages and context' do |t|
7
- t.text :content, null: false, comment: 'The conversation message/utterance content'
8
- t.text :source, default: '', comment: 'From where the content came (empty string if unknown)'
9
- t.integer :access_count, default: 0, null: false, comment: 'Number of times this node has been accessed/retrieved'
10
- t.timestamptz :created_at, default: -> { 'CURRENT_TIMESTAMP' }, comment: 'When this memory was created'
11
- t.timestamptz :updated_at, default: -> { 'CURRENT_TIMESTAMP' }, comment: 'When this memory was last modified'
12
- t.timestamptz :last_accessed, default: -> { 'CURRENT_TIMESTAMP' }, comment: 'When this memory was last accessed'
13
- t.integer :token_count, comment: 'Number of tokens in the content (for context budget management)'
14
- t.boolean :in_working_memory, default: false, comment: 'Whether this memory is currently in working memory'
15
- t.bigint :robot_id, null: false, comment: 'ID of the robot that owns this memory'
16
- t.vector :embedding, limit: 2000, comment: 'Vector embedding (max 2000 dimensions) for semantic search'
17
- t.integer :embedding_dimension, comment: 'Actual number of dimensions used in the embedding vector (max 2000)'
18
- end
19
-
20
- # Basic indexes for common queries
21
- add_index :nodes, :created_at, name: 'idx_nodes_created_at'
22
- add_index :nodes, :updated_at, name: 'idx_nodes_updated_at'
23
- add_index :nodes, :last_accessed, name: 'idx_nodes_last_accessed'
24
- add_index :nodes, :access_count, name: 'idx_nodes_access_count'
25
- add_index :nodes, :robot_id, name: 'idx_nodes_robot_id'
26
- add_index :nodes, :source, name: 'idx_nodes_source'
27
- add_index :nodes, :in_working_memory, name: 'idx_nodes_in_working_memory'
28
-
29
- # Add check constraint for embedding dimensions
30
- # Only validates when embedding_dimension is provided (allows NULL for nodes without embeddings)
31
- execute <<-SQL
32
- ALTER TABLE nodes ADD CONSTRAINT check_embedding_dimension
33
- CHECK (embedding_dimension IS NULL OR (embedding_dimension > 0 AND embedding_dimension <= 2000))
34
- SQL
35
- end
36
-
37
- # Foreign key to robots table (outside table_exists check so it gets added even if table already exists)
38
- unless foreign_key_exists?(:nodes, :robots, column: :robot_id)
39
- add_foreign_key :nodes, :robots, column: :robot_id, primary_key: :id, on_delete: :cascade
40
- end
41
- end
42
- end
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateTags < ActiveRecord::Migration[7.1]
4
- def change
5
- # Create tags table with unique tag names
6
- unless table_exists?(:tags)
7
- create_table :tags, comment: 'Unique tag names for categorization' do |t|
8
- t.text :name, null: false, comment: 'Hierarchical tag in format: root:level1:level2 (e.g., database:postgresql:timescaledb)'
9
- t.timestamptz :created_at, default: -> { 'CURRENT_TIMESTAMP' }, comment: 'When this tag was created'
10
- end
11
-
12
- add_index :tags, :name, unique: true, name: 'idx_tags_name_unique'
13
- add_index :tags, :name, using: :btree, opclass: :text_pattern_ops, name: 'idx_tags_name_pattern'
14
- end
15
-
16
- # Create join table for many-to-many relationship
17
- unless table_exists?(:node_tags)
18
- create_table :node_tags, comment: 'Join table connecting nodes to tags (many-to-many)' do |t|
19
- t.bigint :node_id, null: false, comment: 'ID of the node being tagged'
20
- t.bigint :tag_id, null: false, comment: 'ID of the tag being applied'
21
- t.timestamptz :created_at, default: -> { 'CURRENT_TIMESTAMP' }, comment: 'When this association was created'
22
- end
23
-
24
- add_index :node_tags, [:node_id, :tag_id], unique: true, name: 'idx_node_tags_unique'
25
- add_index :node_tags, :node_id, name: 'idx_node_tags_node_id'
26
- add_index :node_tags, :tag_id, name: 'idx_node_tags_tag_id'
27
- end
28
-
29
- # Add foreign keys (outside table_exists check so they get added even if table already exists)
30
- unless foreign_key_exists?(:node_tags, :nodes, column: :node_id)
31
- add_foreign_key :node_tags, :nodes, column: :node_id, primary_key: :id, on_delete: :cascade
32
- end
33
-
34
- unless foreign_key_exists?(:node_tags, :tags, column: :tag_id)
35
- add_foreign_key :node_tags, :tags, column: :tag_id, primary_key: :id, on_delete: :cascade
36
- end
37
- end
38
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class AddNodeVectorIndexes < ActiveRecord::Migration[7.1]
4
- def up
5
- # Vector similarity search index (HNSW for better performance)
6
- execute <<-SQL
7
- CREATE INDEX IF NOT EXISTS idx_nodes_embedding ON nodes
8
- USING hnsw (embedding vector_cosine_ops)
9
- WITH (m = 16, ef_construction = 64)
10
- SQL
11
-
12
- # Full-text search on conversation content
13
- execute <<-SQL
14
- CREATE INDEX IF NOT EXISTS idx_nodes_content_gin ON nodes
15
- USING gin(to_tsvector('english', content))
16
- SQL
17
-
18
- # Trigram indexes for fuzzy matching on conversation content
19
- execute <<-SQL
20
- CREATE INDEX IF NOT EXISTS idx_nodes_content_trgm ON nodes
21
- USING gin(content gin_trgm_ops)
22
- SQL
23
- end
24
-
25
- def down
26
- remove_index :nodes, name: 'idx_nodes_embedding'
27
- remove_index :nodes, name: 'idx_nodes_content_gin'
28
- remove_index :nodes, name: 'idx_nodes_content_trgm'
29
- end
30
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class AddContentHashToNodes < ActiveRecord::Migration[7.1]
4
- def change
5
- unless column_exists?(:nodes, :content_hash)
6
- # Add content_hash column for SHA-256 hash of content (64 hex characters)
7
- add_column :nodes, :content_hash, :string, limit: 64,
8
- comment: 'SHA-256 hash of content for deduplication'
9
-
10
- # Unique index to prevent duplicate content
11
- add_index :nodes, :content_hash, unique: true, name: 'idx_nodes_content_hash_unique'
12
- end
13
- end
14
- end
@@ -1,35 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateRobotNodes < ActiveRecord::Migration[7.1]
4
- def change
5
- unless table_exists?(:robot_nodes)
6
- create_table :robot_nodes, comment: 'Join table connecting robots to nodes (many-to-many)' do |t|
7
- t.bigint :robot_id, null: false, comment: 'ID of the robot that remembered this node'
8
- t.bigint :node_id, null: false, comment: 'ID of the node being remembered'
9
- t.timestamptz :first_remembered_at, default: -> { 'CURRENT_TIMESTAMP' },
10
- comment: 'When this robot first remembered this content'
11
- t.timestamptz :last_remembered_at, default: -> { 'CURRENT_TIMESTAMP' },
12
- comment: 'When this robot last tried to remember this content'
13
- t.integer :remember_count, default: 1, null: false,
14
- comment: 'Number of times this robot has tried to remember this content'
15
- t.timestamptz :created_at, default: -> { 'CURRENT_TIMESTAMP' }
16
- t.timestamptz :updated_at, default: -> { 'CURRENT_TIMESTAMP' }
17
- end
18
-
19
- # Unique constraint: each robot can only link to a node once
20
- add_index :robot_nodes, [:robot_id, :node_id], unique: true, name: 'idx_robot_nodes_unique'
21
- add_index :robot_nodes, :robot_id, name: 'idx_robot_nodes_robot_id'
22
- add_index :robot_nodes, :node_id, name: 'idx_robot_nodes_node_id'
23
- add_index :robot_nodes, :last_remembered_at, name: 'idx_robot_nodes_last_remembered_at'
24
- end
25
-
26
- # Add foreign keys
27
- unless foreign_key_exists?(:robot_nodes, :robots, column: :robot_id)
28
- add_foreign_key :robot_nodes, :robots, column: :robot_id, primary_key: :id, on_delete: :cascade
29
- end
30
-
31
- unless foreign_key_exists?(:robot_nodes, :nodes, column: :node_id)
32
- add_foreign_key :robot_nodes, :nodes, column: :node_id, primary_key: :id, on_delete: :cascade
33
- end
34
- end
35
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class RemoveSourceAndRobotIdFromNodes < ActiveRecord::Migration[7.1]
4
- def change
5
- # Remove foreign key constraint first
6
- if foreign_key_exists?(:nodes, :robots, column: :robot_id)
7
- remove_foreign_key :nodes, :robots, column: :robot_id
8
- end
9
-
10
- # Remove indexes
11
- if index_exists?(:nodes, :robot_id, name: 'idx_nodes_robot_id')
12
- remove_index :nodes, name: 'idx_nodes_robot_id'
13
- end
14
-
15
- if index_exists?(:nodes, :source, name: 'idx_nodes_source')
16
- remove_index :nodes, name: 'idx_nodes_source'
17
- end
18
-
19
- # Remove columns
20
- if column_exists?(:nodes, :robot_id)
21
- remove_column :nodes, :robot_id
22
- end
23
-
24
- if column_exists?(:nodes, :source)
25
- remove_column :nodes, :source
26
- end
27
- end
28
- end
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class CreateWorkingMemories < ActiveRecord::Migration[7.1]
4
- def change
5
- create_table :working_memories, comment: 'Per-robot working memory state (optional persistence)' do |t|
6
- t.bigint :robot_id, null: false, comment: 'Robot whose working memory this belongs to'
7
- t.bigint :node_id, null: false, comment: 'Node currently in working memory'
8
- t.timestamptz :added_at, default: -> { 'CURRENT_TIMESTAMP' }, comment: 'When node was added to working memory'
9
- t.integer :token_count, comment: 'Cached token count for budget tracking'
10
- end
11
-
12
- add_index :working_memories, :robot_id, name: 'idx_working_memories_robot_id'
13
- add_index :working_memories, :node_id, name: 'idx_working_memories_node_id'
14
- add_index :working_memories, [:robot_id, :node_id], unique: true, name: 'idx_working_memories_unique'
15
-
16
- add_foreign_key :working_memories, :robots, on_delete: :cascade
17
- add_foreign_key :working_memories, :nodes, on_delete: :cascade
18
- end
19
- end
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class RemoveUnusedColumns < ActiveRecord::Migration[7.1]
4
- def change
5
- # Remove in_working_memory from nodes - now tracked per-robot in working_memories table
6
- remove_index :nodes, name: 'idx_nodes_in_working_memory', if_exists: true
7
- remove_column :nodes, :in_working_memory, :boolean, default: false
8
-
9
- # Remove unused metadata column from robots
10
- remove_column :robots, :metadata, :jsonb
11
- end
12
- end
@@ -1,40 +0,0 @@
1
- # public.working_memories
2
-
3
- ## Description
4
-
5
- Per-robot working memory state (optional persistence)
6
-
7
- ## Columns
8
-
9
- | Name | Type | Default | Nullable | Children | Parents | Comment |
10
- | ---- | ---- | ------- | -------- | -------- | ------- | ------- |
11
- | id | bigint | nextval('working_memories_id_seq'::regclass) | false | | | |
12
- | robot_id | bigint | | false | | [public.robots](public.robots.md) | Robot whose working memory this belongs to |
13
- | node_id | bigint | | false | | [public.nodes](public.nodes.md) | Node currently in working memory |
14
- | added_at | timestamp with time zone | CURRENT_TIMESTAMP | true | | | When node was added to working memory |
15
- | token_count | integer | | true | | | Cached token count for budget tracking |
16
-
17
- ## Constraints
18
-
19
- | Name | Type | Definition |
20
- | ---- | ---- | ---------- |
21
- | fk_rails_4b7c3eb07b | FOREIGN KEY | FOREIGN KEY (robot_id) REFERENCES robots(id) ON DELETE CASCADE |
22
- | fk_rails_2c1d8b383c | FOREIGN KEY | FOREIGN KEY (node_id) REFERENCES nodes(id) ON DELETE CASCADE |
23
- | working_memories_pkey | PRIMARY KEY | PRIMARY KEY (id) |
24
-
25
- ## Indexes
26
-
27
- | Name | Definition |
28
- | ---- | ---------- |
29
- | working_memories_pkey | CREATE UNIQUE INDEX working_memories_pkey ON public.working_memories USING btree (id) |
30
- | idx_working_memories_robot_id | CREATE INDEX idx_working_memories_robot_id ON public.working_memories USING btree (robot_id) |
31
- | idx_working_memories_node_id | CREATE INDEX idx_working_memories_node_id ON public.working_memories USING btree (node_id) |
32
- | idx_working_memories_unique | CREATE UNIQUE INDEX idx_working_memories_unique ON public.working_memories USING btree (robot_id, node_id) |
33
-
34
- ## Relations
35
-
36
- ![er](public.working_memories.svg)
37
-
38
- ---
39
-
40
- > Generated by [tbls](https://github.com/k1LoW/tbls)