htm 0.0.1

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 (155) hide show
  1. checksums.yaml +7 -0
  2. data/.architecture/decisions/adrs/001-use-postgresql-timescaledb-storage.md +227 -0
  3. data/.architecture/decisions/adrs/002-two-tier-memory-architecture.md +322 -0
  4. data/.architecture/decisions/adrs/003-ollama-default-embedding-provider.md +339 -0
  5. data/.architecture/decisions/adrs/004-multi-robot-shared-memory-hive-mind.md +374 -0
  6. data/.architecture/decisions/adrs/005-rag-based-retrieval-with-hybrid-search.md +443 -0
  7. data/.architecture/decisions/adrs/006-context-assembly-strategies.md +444 -0
  8. data/.architecture/decisions/adrs/007-working-memory-eviction-strategy.md +461 -0
  9. data/.architecture/decisions/adrs/008-robot-identification-system.md +550 -0
  10. data/.architecture/decisions/adrs/009-never-forget-explicit-deletion-only.md +570 -0
  11. data/.architecture/decisions/adrs/010-redis-working-memory-rejected.md +323 -0
  12. data/.architecture/decisions/adrs/011-database-side-embedding-generation-with-pgai.md +585 -0
  13. data/.architecture/decisions/adrs/012-llm-driven-ontology-topic-extraction.md +583 -0
  14. data/.architecture/decisions/adrs/013-activerecord-orm-and-many-to-many-tagging.md +299 -0
  15. data/.architecture/decisions/adrs/014-client-side-embedding-generation-workflow.md +569 -0
  16. data/.architecture/decisions/adrs/015-hierarchical-tag-ontology-and-llm-extraction.md +701 -0
  17. data/.architecture/decisions/adrs/016-async-embedding-and-tag-generation.md +694 -0
  18. data/.architecture/members.yml +144 -0
  19. data/.architecture/reviews/2025-10-29-llm-configuration-and-async-processing-review.md +1137 -0
  20. data/.architecture/reviews/initial-system-analysis.md +330 -0
  21. data/.envrc +32 -0
  22. data/.irbrc +145 -0
  23. data/CHANGELOG.md +150 -0
  24. data/COMMITS.md +196 -0
  25. data/LICENSE +21 -0
  26. data/README.md +1347 -0
  27. data/Rakefile +51 -0
  28. data/SETUP.md +268 -0
  29. data/config/database.yml +67 -0
  30. data/db/migrate/20250101000001_enable_extensions.rb +14 -0
  31. data/db/migrate/20250101000002_create_robots.rb +14 -0
  32. data/db/migrate/20250101000003_create_nodes.rb +42 -0
  33. data/db/migrate/20250101000005_create_tags.rb +38 -0
  34. data/db/migrate/20250101000007_add_node_vector_indexes.rb +30 -0
  35. data/db/schema.sql +473 -0
  36. data/db/seed_data/README.md +100 -0
  37. data/db/seed_data/presidents.md +136 -0
  38. data/db/seed_data/states.md +151 -0
  39. data/db/seeds.rb +208 -0
  40. data/dbdoc/README.md +173 -0
  41. data/dbdoc/public.node_stats.md +48 -0
  42. data/dbdoc/public.node_stats.svg +41 -0
  43. data/dbdoc/public.node_tags.md +40 -0
  44. data/dbdoc/public.node_tags.svg +112 -0
  45. data/dbdoc/public.nodes.md +54 -0
  46. data/dbdoc/public.nodes.svg +118 -0
  47. data/dbdoc/public.nodes_tags.md +39 -0
  48. data/dbdoc/public.nodes_tags.svg +112 -0
  49. data/dbdoc/public.ontology_structure.md +48 -0
  50. data/dbdoc/public.ontology_structure.svg +38 -0
  51. data/dbdoc/public.operations_log.md +42 -0
  52. data/dbdoc/public.operations_log.svg +130 -0
  53. data/dbdoc/public.relationships.md +39 -0
  54. data/dbdoc/public.relationships.svg +41 -0
  55. data/dbdoc/public.robot_activity.md +46 -0
  56. data/dbdoc/public.robot_activity.svg +35 -0
  57. data/dbdoc/public.robots.md +35 -0
  58. data/dbdoc/public.robots.svg +90 -0
  59. data/dbdoc/public.schema_migrations.md +29 -0
  60. data/dbdoc/public.schema_migrations.svg +26 -0
  61. data/dbdoc/public.tags.md +35 -0
  62. data/dbdoc/public.tags.svg +60 -0
  63. data/dbdoc/public.topic_relationships.md +45 -0
  64. data/dbdoc/public.topic_relationships.svg +32 -0
  65. data/dbdoc/schema.json +1437 -0
  66. data/dbdoc/schema.svg +154 -0
  67. data/docs/api/database.md +806 -0
  68. data/docs/api/embedding-service.md +532 -0
  69. data/docs/api/htm.md +797 -0
  70. data/docs/api/index.md +259 -0
  71. data/docs/api/long-term-memory.md +1096 -0
  72. data/docs/api/working-memory.md +665 -0
  73. data/docs/architecture/adrs/001-postgresql-timescaledb.md +314 -0
  74. data/docs/architecture/adrs/002-two-tier-memory.md +411 -0
  75. data/docs/architecture/adrs/003-ollama-embeddings.md +421 -0
  76. data/docs/architecture/adrs/004-hive-mind.md +437 -0
  77. data/docs/architecture/adrs/005-rag-retrieval.md +531 -0
  78. data/docs/architecture/adrs/006-context-assembly.md +496 -0
  79. data/docs/architecture/adrs/007-eviction-strategy.md +645 -0
  80. data/docs/architecture/adrs/008-robot-identification.md +625 -0
  81. data/docs/architecture/adrs/009-never-forget.md +648 -0
  82. data/docs/architecture/adrs/010-redis-working-memory-rejected.md +323 -0
  83. data/docs/architecture/adrs/011-pgai-integration.md +494 -0
  84. data/docs/architecture/adrs/index.md +215 -0
  85. data/docs/architecture/hive-mind.md +736 -0
  86. data/docs/architecture/index.md +351 -0
  87. data/docs/architecture/overview.md +538 -0
  88. data/docs/architecture/two-tier-memory.md +873 -0
  89. data/docs/assets/css/custom.css +83 -0
  90. data/docs/assets/images/htm-core-components.svg +63 -0
  91. data/docs/assets/images/htm-database-schema.svg +93 -0
  92. data/docs/assets/images/htm-hive-mind-architecture.svg +125 -0
  93. data/docs/assets/images/htm-importance-scoring-framework.svg +83 -0
  94. data/docs/assets/images/htm-layered-architecture.svg +71 -0
  95. data/docs/assets/images/htm-long-term-memory-architecture.svg +115 -0
  96. data/docs/assets/images/htm-working-memory-architecture.svg +120 -0
  97. data/docs/assets/images/htm.jpg +0 -0
  98. data/docs/assets/images/htm_demo.gif +0 -0
  99. data/docs/assets/js/mathjax.js +18 -0
  100. data/docs/assets/videos/htm_video.mp4 +0 -0
  101. data/docs/database_rake_tasks.md +322 -0
  102. data/docs/development/contributing.md +787 -0
  103. data/docs/development/index.md +336 -0
  104. data/docs/development/schema.md +596 -0
  105. data/docs/development/setup.md +719 -0
  106. data/docs/development/testing.md +819 -0
  107. data/docs/guides/adding-memories.md +824 -0
  108. data/docs/guides/context-assembly.md +1009 -0
  109. data/docs/guides/getting-started.md +577 -0
  110. data/docs/guides/index.md +118 -0
  111. data/docs/guides/long-term-memory.md +941 -0
  112. data/docs/guides/multi-robot.md +866 -0
  113. data/docs/guides/recalling-memories.md +927 -0
  114. data/docs/guides/search-strategies.md +953 -0
  115. data/docs/guides/working-memory.md +717 -0
  116. data/docs/index.md +214 -0
  117. data/docs/installation.md +477 -0
  118. data/docs/multi_framework_support.md +519 -0
  119. data/docs/quick-start.md +655 -0
  120. data/docs/setup_local_database.md +302 -0
  121. data/docs/using_rake_tasks_in_your_app.md +383 -0
  122. data/examples/basic_usage.rb +93 -0
  123. data/examples/cli_app/README.md +317 -0
  124. data/examples/cli_app/htm_cli.rb +270 -0
  125. data/examples/custom_llm_configuration.rb +183 -0
  126. data/examples/example_app/Rakefile +71 -0
  127. data/examples/example_app/app.rb +206 -0
  128. data/examples/sinatra_app/Gemfile +21 -0
  129. data/examples/sinatra_app/app.rb +335 -0
  130. data/lib/htm/active_record_config.rb +113 -0
  131. data/lib/htm/configuration.rb +342 -0
  132. data/lib/htm/database.rb +594 -0
  133. data/lib/htm/embedding_service.rb +115 -0
  134. data/lib/htm/errors.rb +34 -0
  135. data/lib/htm/job_adapter.rb +154 -0
  136. data/lib/htm/jobs/generate_embedding_job.rb +65 -0
  137. data/lib/htm/jobs/generate_tags_job.rb +82 -0
  138. data/lib/htm/long_term_memory.rb +965 -0
  139. data/lib/htm/models/node.rb +109 -0
  140. data/lib/htm/models/node_tag.rb +33 -0
  141. data/lib/htm/models/robot.rb +52 -0
  142. data/lib/htm/models/tag.rb +76 -0
  143. data/lib/htm/railtie.rb +76 -0
  144. data/lib/htm/sinatra.rb +157 -0
  145. data/lib/htm/tag_service.rb +135 -0
  146. data/lib/htm/tasks.rb +38 -0
  147. data/lib/htm/version.rb +5 -0
  148. data/lib/htm/working_memory.rb +182 -0
  149. data/lib/htm.rb +400 -0
  150. data/lib/tasks/db.rake +19 -0
  151. data/lib/tasks/htm.rake +147 -0
  152. data/lib/tasks/jobs.rake +312 -0
  153. data/mkdocs.yml +190 -0
  154. data/scripts/install_local_database.sh +309 -0
  155. metadata +341 -0
data/docs/api/htm.md ADDED
@@ -0,0 +1,797 @@
1
+ # HTM Class
2
+
3
+ The main interface for HTM's intelligent memory management system.
4
+
5
+ ## Overview
6
+
7
+ `HTM` is the primary class that orchestrates the two-tier memory system:
8
+
9
+ - **Working Memory**: Token-limited active context for immediate LLM use
10
+ - **Long-term Memory**: Durable PostgreSQL storage
11
+
12
+ Key features:
13
+
14
+ - Never forgets unless explicitly told (`forget`)
15
+ - RAG-based retrieval (temporal + semantic search)
16
+ - Multi-robot "hive mind" - all robots share global memory
17
+ - Relationship graphs for knowledge connections
18
+ - Time-series optimized with TimescaleDB
19
+
20
+ ## Class Definition
21
+
22
+ ```ruby
23
+ class HTM
24
+ attr_reader :robot_id, :robot_name, :working_memory, :long_term_memory
25
+ end
26
+ ```
27
+
28
+ ## Initialization
29
+
30
+ ### `new(**options)` {: #new }
31
+
32
+ Create a new HTM instance.
33
+
34
+ ```ruby
35
+ HTM.new(
36
+ working_memory_size: 128_000,
37
+ robot_id: nil,
38
+ robot_name: nil,
39
+ db_config: nil,
40
+ embedding_service: :ollama,
41
+ embedding_model: 'gpt-oss'
42
+ )
43
+ ```
44
+
45
+ #### Parameters
46
+
47
+ | Parameter | Type | Default | Description |
48
+ |-----------|------|---------|-------------|
49
+ | `working_memory_size` | Integer | `128_000` | Maximum tokens for working memory |
50
+ | `robot_id` | String, nil | Auto-generated UUID | Unique identifier for this robot |
51
+ | `robot_name` | String, nil | `"robot_#{id[0..7]}"` | Human-readable name |
52
+ | `db_config` | Hash, nil | From `ENV['HTM_DBURL']` | Database configuration |
53
+ | `embedding_service` | Symbol | `:ollama` | Embedding provider (`:ollama`, `:openai`, `:cohere`, `:local`) |
54
+ | `embedding_model` | String | `'gpt-oss'` | Model name for embeddings |
55
+
56
+ #### Returns
57
+
58
+ - `HTM` instance
59
+
60
+ #### Examples
61
+
62
+ ```ruby
63
+ # Basic initialization
64
+ htm = HTM.new(robot_name: "Code Assistant")
65
+
66
+ # Custom working memory size
67
+ htm = HTM.new(
68
+ robot_name: "Large Context Bot",
69
+ working_memory_size: 256_000
70
+ )
71
+
72
+ # OpenAI embeddings
73
+ htm = HTM.new(
74
+ robot_name: "Research Bot",
75
+ embedding_service: :openai,
76
+ embedding_model: 'text-embedding-3-small'
77
+ )
78
+
79
+ # Custom database
80
+ htm = HTM.new(
81
+ db_config: {
82
+ host: 'localhost',
83
+ port: 5432,
84
+ dbname: 'htm_db',
85
+ user: 'postgres',
86
+ password: 'secret'
87
+ }
88
+ )
89
+ ```
90
+
91
+ ---
92
+
93
+ ## Instance Attributes
94
+
95
+ ### `robot_id` {: #robot_id }
96
+
97
+ Unique identifier for this robot instance.
98
+
99
+ - **Type**: String (UUID format)
100
+ - **Read-only**: Yes
101
+
102
+ ```ruby
103
+ htm.robot_id # => "a1b2c3d4-e5f6-..."
104
+ ```
105
+
106
+ ### `robot_name` {: #robot_name }
107
+
108
+ Human-readable name for this robot.
109
+
110
+ - **Type**: String
111
+ - **Read-only**: Yes
112
+
113
+ ```ruby
114
+ htm.robot_name # => "Code Assistant"
115
+ ```
116
+
117
+ ### `working_memory` {: #working_memory }
118
+
119
+ The working memory instance.
120
+
121
+ - **Type**: `HTM::WorkingMemory`
122
+ - **Read-only**: Yes
123
+
124
+ ```ruby
125
+ htm.working_memory.token_count # => 45234
126
+ ```
127
+
128
+ ### `long_term_memory` {: #long_term_memory }
129
+
130
+ The long-term memory instance.
131
+
132
+ - **Type**: `HTM::LongTermMemory`
133
+ - **Read-only**: Yes
134
+
135
+ ```ruby
136
+ htm.long_term_memory.stats # => {...}
137
+ ```
138
+
139
+ ---
140
+
141
+ ## Public Methods
142
+
143
+ ### `add_node(key, value, **options)` {: #add_node }
144
+
145
+ Add a new memory node to both working and long-term memory.
146
+
147
+ ```ruby
148
+ add_node(key, value,
149
+ type: nil,
150
+ category: nil,
151
+ importance: 1.0,
152
+ related_to: [],
153
+ tags: []
154
+ )
155
+ ```
156
+
157
+ #### Parameters
158
+
159
+ | Parameter | Type | Default | Description |
160
+ |-----------|------|---------|-------------|
161
+ | `key` | String | *required* | Unique identifier for this node |
162
+ | `value` | String | *required* | Content of the memory |
163
+ | `type` | Symbol, nil | `nil` | Memory type (`:fact`, `:context`, `:code`, `:preference`, `:decision`, `:question`) |
164
+ | `category` | String, nil | `nil` | Optional category for organization |
165
+ | `importance` | Float | `1.0` | Importance score (0.0-10.0) |
166
+ | `related_to` | Array\<String\> | `[]` | Keys of related nodes |
167
+ | `tags` | Array\<String\> | `[]` | Tags for categorization |
168
+
169
+ #### Returns
170
+
171
+ - `Integer` - Database ID of the created node
172
+
173
+ #### Side Effects
174
+
175
+ - Stores node in PostgreSQL with vector embedding
176
+ - Adds node to working memory (evicts if needed)
177
+ - Creates relationships to `related_to` nodes
178
+ - Adds tags to the node
179
+ - Logs operation to `operations_log` table
180
+ - Updates robot activity timestamp
181
+
182
+ #### Examples
183
+
184
+ ```ruby
185
+ # Simple fact
186
+ htm.add_node("db_choice", "We chose PostgreSQL for its reliability")
187
+
188
+ # Architectural decision
189
+ htm.add_node(
190
+ "api_gateway_decision",
191
+ "Decided to use Kong as API gateway for rate limiting and auth",
192
+ type: :decision,
193
+ importance: 9.0,
194
+ tags: ["architecture", "api", "gateway"],
195
+ related_to: ["microservices_architecture"]
196
+ )
197
+
198
+ # Code snippet
199
+ code = <<~RUBY
200
+ def calculate_total(items)
201
+ items.sum(&:price)
202
+ end
203
+ RUBY
204
+
205
+ htm.add_node(
206
+ "total_calculation_v1",
207
+ code,
208
+ type: :code,
209
+ category: "helpers",
210
+ importance: 5.0,
211
+ tags: ["ruby", "calculation"]
212
+ )
213
+
214
+ # User preference
215
+ htm.add_node(
216
+ "user_123_timezone",
217
+ "User prefers UTC timezone for all timestamps",
218
+ type: :preference,
219
+ category: "user_settings",
220
+ importance: 6.0
221
+ )
222
+ ```
223
+
224
+ #### Notes
225
+
226
+ - The `key` must be unique across all nodes
227
+ - Embeddings are generated automatically
228
+ - Token count is calculated automatically
229
+ - If working memory is full, less important nodes are evicted
230
+
231
+ ---
232
+
233
+ ### `recall(timeframe:, topic:, **options)` {: #recall }
234
+
235
+ Recall memories from a timeframe and topic using RAG-based retrieval.
236
+
237
+ ```ruby
238
+ recall(
239
+ timeframe:,
240
+ topic:,
241
+ limit: 20,
242
+ strategy: :vector
243
+ )
244
+ ```
245
+
246
+ #### Parameters
247
+
248
+ | Parameter | Type | Default | Description |
249
+ |-----------|------|---------|-------------|
250
+ | `timeframe` | String, Range | *required* | Time range (e.g., `"last week"`, `7.days.ago..Time.now`) |
251
+ | `topic` | String | *required* | Topic to search for |
252
+ | `limit` | Integer | `20` | Maximum number of nodes to retrieve |
253
+ | `strategy` | Symbol | `:vector` | Search strategy (`:vector`, `:fulltext`, `:hybrid`) |
254
+
255
+ #### Timeframe Formats
256
+
257
+ String format (natural language):
258
+
259
+ - `"last week"` - Last 7 days
260
+ - `"yesterday"` - Previous day
261
+ - `"last N days"` - Last N days (e.g., "last 30 days")
262
+ - `"this month"` - Current month to now
263
+ - `"last month"` - Previous calendar month
264
+ - Default (unrecognized) - Last 24 hours
265
+
266
+ Range format:
267
+
268
+ - `Time` range: `(Time.now - 7*24*3600)..Time.now`
269
+ - `Date` range: `Date.today-7..Date.today`
270
+
271
+ #### Search Strategies
272
+
273
+ | Strategy | Description | Use Case |
274
+ |----------|-------------|----------|
275
+ | `:vector` | Semantic similarity using embeddings | Find conceptually related content |
276
+ | `:fulltext` | PostgreSQL full-text search | Find exact terms and phrases |
277
+ | `:hybrid` | Fulltext prefilter + vector ranking | Best accuracy + semantic understanding |
278
+
279
+ #### Returns
280
+
281
+ - `Array<Hash>` - Retrieved memory nodes
282
+
283
+ Each hash contains:
284
+
285
+ ```ruby
286
+ {
287
+ "id" => 123, # Database ID
288
+ "key" => "node_key", # Node identifier
289
+ "value" => "content...", # Node content
290
+ "type" => "fact", # Node type
291
+ "category" => "architecture", # Category
292
+ "importance" => 8.0, # Importance score
293
+ "created_at" => "2025-01-15...", # Creation timestamp
294
+ "robot_id" => "abc123...", # Robot that created it
295
+ "token_count" => 125, # Token count
296
+ "similarity" => 0.87 # Similarity score (vector/hybrid only)
297
+ # or "rank" => 0.456 # Rank score (fulltext only)
298
+ }
299
+ ```
300
+
301
+ #### Side Effects
302
+
303
+ - Adds recalled nodes to working memory
304
+ - Evicts existing nodes if working memory is full
305
+ - Logs operation to `operations_log` table
306
+ - Updates robot activity timestamp
307
+
308
+ #### Examples
309
+
310
+ ```ruby
311
+ # Vector semantic search
312
+ memories = htm.recall(
313
+ timeframe: "last week",
314
+ topic: "database performance optimization"
315
+ )
316
+
317
+ # Fulltext search for exact phrases
318
+ memories = htm.recall(
319
+ timeframe: "last 30 days",
320
+ topic: "PostgreSQL connection pooling",
321
+ strategy: :fulltext,
322
+ limit: 10
323
+ )
324
+
325
+ # Hybrid search (best of both)
326
+ memories = htm.recall(
327
+ timeframe: "this month",
328
+ topic: "API rate limiting implementation",
329
+ strategy: :hybrid,
330
+ limit: 15
331
+ )
332
+
333
+ # Custom time range
334
+ start_time = Time.new(2025, 1, 1)
335
+ end_time = Time.now
336
+
337
+ memories = htm.recall(
338
+ timeframe: start_time..end_time,
339
+ topic: "security vulnerabilities",
340
+ limit: 50
341
+ )
342
+
343
+ # Process results
344
+ memories.each do |memory|
345
+ puts "#{memory['created_at']}: #{memory['value']}"
346
+ puts " Similarity: #{memory['similarity']}" if memory['similarity']
347
+ puts " Robot: #{memory['robot_id']}"
348
+ end
349
+ ```
350
+
351
+ #### Performance Notes
352
+
353
+ - Vector search: Best for semantic understanding, requires embedding generation
354
+ - Fulltext search: Fastest for exact matches, no embedding overhead
355
+ - Hybrid search: Slower but most accurate, combines both approaches
356
+
357
+ ---
358
+
359
+ ### `retrieve(key)` {: #retrieve }
360
+
361
+ Retrieve a specific memory node by its key.
362
+
363
+ ```ruby
364
+ retrieve(key)
365
+ ```
366
+
367
+ #### Parameters
368
+
369
+ | Parameter | Type | Description |
370
+ |-----------|------|-------------|
371
+ | `key` | String | Key of the node to retrieve |
372
+
373
+ #### Returns
374
+
375
+ - `Hash` - Node data if found
376
+ - `nil` - If node doesn't exist
377
+
378
+ #### Side Effects
379
+
380
+ - Updates `last_accessed` timestamp for the node
381
+ - Logs operation to `operations_log` table
382
+
383
+ #### Examples
384
+
385
+ ```ruby
386
+ # Retrieve a node
387
+ node = htm.retrieve("api_decision_001")
388
+
389
+ if node
390
+ puts node['value']
391
+ puts "Created: #{node['created_at']}"
392
+ puts "Importance: #{node['importance']}"
393
+ else
394
+ puts "Node not found"
395
+ end
396
+
397
+ # Use retrieved data
398
+ config = htm.retrieve("database_config")
399
+ db_url = JSON.parse(config['value'])['url'] if config
400
+ ```
401
+
402
+ ---
403
+
404
+ ### `forget(key, confirm:)` {: #forget }
405
+
406
+ Explicitly delete a memory node. Requires confirmation to prevent accidental deletion.
407
+
408
+ ```ruby
409
+ forget(key, confirm: :confirmed)
410
+ ```
411
+
412
+ #### Parameters
413
+
414
+ | Parameter | Type | Description |
415
+ |-----------|------|-------------|
416
+ | `key` | String | Key of the node to delete |
417
+ | `confirm` | Symbol | Must be `:confirmed` to proceed |
418
+
419
+ #### Returns
420
+
421
+ - `true` - If successfully deleted
422
+
423
+ #### Raises
424
+
425
+ - `ArgumentError` - If `confirm` is not `:confirmed`
426
+
427
+ #### Side Effects
428
+
429
+ - Deletes node from PostgreSQL
430
+ - Removes node from working memory
431
+ - Logs operation before deletion
432
+ - Updates robot activity timestamp
433
+
434
+ #### Examples
435
+
436
+ ```ruby
437
+ # Correct usage
438
+ htm.forget("temp_note_123", confirm: :confirmed)
439
+
440
+ # This will raise ArgumentError
441
+ htm.forget("temp_note_123") # Missing confirm parameter
442
+
443
+ # Safe deletion with verification
444
+ if htm.retrieve("old_data")
445
+ htm.forget("old_data", confirm: :confirmed)
446
+ puts "Deleted old_data"
447
+ end
448
+ ```
449
+
450
+ #### Notes
451
+
452
+ - This is the **only** way to delete data from HTM
453
+ - Deletion is permanent and cannot be undone
454
+ - Related relationships and tags are also deleted (CASCADE)
455
+
456
+ ---
457
+
458
+ ### `create_context(strategy:, max_tokens:)` {: #create_context }
459
+
460
+ Create a context string from working memory for LLM consumption.
461
+
462
+ ```ruby
463
+ create_context(strategy: :balanced, max_tokens: nil)
464
+ ```
465
+
466
+ #### Parameters
467
+
468
+ | Parameter | Type | Default | Description |
469
+ |-----------|------|---------|-------------|
470
+ | `strategy` | Symbol | `:balanced` | Assembly strategy |
471
+ | `max_tokens` | Integer, nil | Working memory max | Optional token limit |
472
+
473
+ #### Assembly Strategies
474
+
475
+ | Strategy | Behavior | Use Case |
476
+ |----------|----------|----------|
477
+ | `:recent` | Most recently accessed first | Prioritize latest information |
478
+ | `:important` | Highest importance scores first | Focus on critical information |
479
+ | `:balanced` | Weighted by importance × recency | Best general-purpose strategy |
480
+
481
+ #### Returns
482
+
483
+ - `String` - Assembled context with nodes separated by `"\n\n"`
484
+
485
+ #### Examples
486
+
487
+ ```ruby
488
+ # Balanced context (default)
489
+ context = htm.create_context(strategy: :balanced)
490
+
491
+ # Recent context with token limit
492
+ context = htm.create_context(
493
+ strategy: :recent,
494
+ max_tokens: 50_000
495
+ )
496
+
497
+ # Important context only
498
+ context = htm.create_context(strategy: :important)
499
+
500
+ # Use in LLM prompt
501
+ prompt = <<~PROMPT
502
+ You are a helpful assistant.
503
+
504
+ Context from memory:
505
+ #{context}
506
+
507
+ User question: #{user_input}
508
+ PROMPT
509
+ ```
510
+
511
+ #### Notes
512
+
513
+ - Nodes are concatenated with double newlines
514
+ - Token limits are respected (stops adding when limit reached)
515
+ - Empty string if working memory is empty
516
+
517
+ ---
518
+
519
+ ### `memory_stats()` {: #memory_stats }
520
+
521
+ Get comprehensive statistics about memory usage.
522
+
523
+ ```ruby
524
+ memory_stats()
525
+ ```
526
+
527
+ #### Returns
528
+
529
+ - `Hash` - Statistics hash
530
+
531
+ Structure:
532
+
533
+ ```ruby
534
+ {
535
+ robot_id: "abc123...",
536
+ robot_name: "Assistant",
537
+
538
+ # Long-term memory stats
539
+ total_nodes: 1234,
540
+ nodes_by_robot: {
541
+ "robot-1" => 500,
542
+ "robot-2" => 734
543
+ },
544
+ nodes_by_type: [
545
+ {"type" => "fact", "count" => 400},
546
+ {"type" => "decision", "count" => 200},
547
+ ...
548
+ ],
549
+ total_relationships: 567,
550
+ total_tags: 890,
551
+ oldest_memory: "2025-01-01 12:00:00",
552
+ newest_memory: "2025-01-15 14:30:00",
553
+ active_robots: 3,
554
+ robot_activity: [...],
555
+ database_size: 12345678,
556
+
557
+ # Working memory stats
558
+ working_memory: {
559
+ current_tokens: 45234,
560
+ max_tokens: 128000,
561
+ utilization: 35.34,
562
+ node_count: 23
563
+ }
564
+ }
565
+ ```
566
+
567
+ #### Examples
568
+
569
+ ```ruby
570
+ stats = htm.memory_stats
571
+
572
+ puts "Total memories: #{stats[:total_nodes]}"
573
+ puts "Working memory: #{stats[:working_memory][:utilization]}% full"
574
+ puts "Active robots: #{stats[:active_robots]}"
575
+
576
+ # Check if working memory is getting full
577
+ if stats[:working_memory][:utilization] > 80
578
+ puts "Warning: Working memory is #{stats[:working_memory][:utilization]}% full"
579
+ end
580
+
581
+ # Display by robot
582
+ stats[:nodes_by_robot].each do |robot_id, count|
583
+ puts "#{robot_id}: #{count} nodes"
584
+ end
585
+ ```
586
+
587
+ ---
588
+
589
+ ### `which_robot_said(topic, limit:)` {: #which_robot_said }
590
+
591
+ Find which robots have discussed a specific topic.
592
+
593
+ ```ruby
594
+ which_robot_said(topic, limit: 100)
595
+ ```
596
+
597
+ #### Parameters
598
+
599
+ | Parameter | Type | Default | Description |
600
+ |-----------|------|---------|-------------|
601
+ | `topic` | String | *required* | Topic to search for |
602
+ | `limit` | Integer | `100` | Maximum results to consider |
603
+
604
+ #### Returns
605
+
606
+ - `Hash` - Robot IDs mapped to mention counts
607
+
608
+ ```ruby
609
+ {
610
+ "robot-abc123" => 15,
611
+ "robot-def456" => 8,
612
+ "robot-ghi789" => 3
613
+ }
614
+ ```
615
+
616
+ #### Examples
617
+
618
+ ```ruby
619
+ # Find who discussed deployment
620
+ robots = htm.which_robot_said("deployment")
621
+ # => {"robot-1" => 12, "robot-2" => 5}
622
+
623
+ # Top contributor
624
+ top_robot, count = robots.max_by { |robot, count| count }
625
+ puts "#{top_robot} mentioned it #{count} times"
626
+
627
+ # Check if specific robot discussed it
628
+ if robots.key?("robot-123")
629
+ puts "Robot-123 discussed deployment #{robots['robot-123']} times"
630
+ end
631
+ ```
632
+
633
+ ---
634
+
635
+ ### `conversation_timeline(topic, limit:)` {: #conversation_timeline }
636
+
637
+ Get a chronological timeline of conversation about a topic.
638
+
639
+ ```ruby
640
+ conversation_timeline(topic, limit: 50)
641
+ ```
642
+
643
+ #### Parameters
644
+
645
+ | Parameter | Type | Default | Description |
646
+ |-----------|------|---------|-------------|
647
+ | `topic` | String | *required* | Topic to search for |
648
+ | `limit` | Integer | `50` | Maximum results |
649
+
650
+ #### Returns
651
+
652
+ - `Array<Hash>` - Timeline entries sorted by timestamp
653
+
654
+ Structure:
655
+
656
+ ```ruby
657
+ [
658
+ {
659
+ timestamp: "2025-01-15 10:30:00",
660
+ robot: "robot-abc123",
661
+ content: "We should consider PostgreSQL...",
662
+ type: "decision"
663
+ },
664
+ {
665
+ timestamp: "2025-01-15 11:45:00",
666
+ robot: "robot-def456",
667
+ content: "Agreed, PostgreSQL has better...",
668
+ type: "fact"
669
+ },
670
+ ...
671
+ ]
672
+ ```
673
+
674
+ #### Examples
675
+
676
+ ```ruby
677
+ # Get timeline
678
+ timeline = htm.conversation_timeline("API design", limit: 20)
679
+
680
+ # Display timeline
681
+ timeline.each do |entry|
682
+ puts "[#{entry[:timestamp]}] #{entry[:robot]}:"
683
+ puts " #{entry[:content]}"
684
+ puts " (#{entry[:type]})"
685
+ puts
686
+ end
687
+
688
+ # Find first mention
689
+ first = timeline.first
690
+ puts "First discussed by #{first[:robot]} at #{first[:timestamp]}"
691
+
692
+ # Group by robot
693
+ by_robot = timeline.group_by { |e| e[:robot] }
694
+ by_robot.each do |robot, entries|
695
+ puts "#{robot}: #{entries.size} contributions"
696
+ end
697
+ ```
698
+
699
+ ---
700
+
701
+ ## Error Handling
702
+
703
+ ### ArgumentError
704
+
705
+ ```ruby
706
+ # Invalid confirm parameter
707
+ htm.forget("key")
708
+ # => ArgumentError: Must pass confirm: :confirmed to delete
709
+
710
+ # Invalid timeframe
711
+ htm.recall(timeframe: nil, topic: "test")
712
+ # => ArgumentError: Invalid timeframe: nil
713
+ ```
714
+
715
+ ### PG::Error
716
+
717
+ ```ruby
718
+ # Database connection issues
719
+ htm = HTM.new(db_config: { host: 'invalid' })
720
+ # => PG::ConnectionBad: could not translate host name...
721
+
722
+ # Duplicate key
723
+ htm.add_node("existing_key", "value")
724
+ # => PG::UniqueViolation: duplicate key value...
725
+ ```
726
+
727
+ ## Best Practices
728
+
729
+ ### Memory Organization
730
+
731
+ ```ruby
732
+ # Use consistent key naming
733
+ htm.add_node("decision_20250115_api_gateway", ...)
734
+ htm.add_node("fact_20250115_database_choice", ...)
735
+
736
+ # Use importance strategically
737
+ htm.add_node(key, value, importance: 9.0) # Critical
738
+ htm.add_node(key, value, importance: 5.0) # Normal
739
+ htm.add_node(key, value, importance: 2.0) # Low priority
740
+
741
+ # Build knowledge graphs
742
+ htm.add_node(
743
+ "api_v2_implementation",
744
+ "...",
745
+ related_to: ["api_v1_design", "authentication_decision"]
746
+ )
747
+ ```
748
+
749
+ ### Search Strategies
750
+
751
+ ```ruby
752
+ # Use vector for semantic understanding
753
+ memories = htm.recall(
754
+ timeframe: "last month",
755
+ topic: "performance issues",
756
+ strategy: :vector # Finds "slow queries", "optimization", etc.
757
+ )
758
+
759
+ # Use fulltext for exact terms
760
+ memories = htm.recall(
761
+ timeframe: "this week",
762
+ topic: "PostgreSQL EXPLAIN ANALYZE",
763
+ strategy: :fulltext # Exact match
764
+ )
765
+
766
+ # Use hybrid for best results
767
+ memories = htm.recall(
768
+ timeframe: "last week",
769
+ topic: "security vulnerability",
770
+ strategy: :hybrid # Accurate + semantic
771
+ )
772
+ ```
773
+
774
+ ### Resource Management
775
+
776
+ ```ruby
777
+ # Check working memory before large operations
778
+ stats = htm.memory_stats
779
+ if stats[:working_memory][:utilization] > 90
780
+ # Maybe explicitly recall less
781
+ end
782
+
783
+ # Use appropriate limits
784
+ htm.recall(topic: "common_topic", limit: 10) # Not 1000
785
+
786
+ # Monitor database size
787
+ if stats[:database_size] > 1_000_000_000 # 1GB
788
+ # Consider archival strategy
789
+ end
790
+ ```
791
+
792
+ ## See Also
793
+
794
+ - [WorkingMemory API](working-memory.md)
795
+ - [LongTermMemory API](long-term-memory.md)
796
+ - [EmbeddingService API](embedding-service.md)
797
+ - [Database API](database.md)