htm 0.0.14 → 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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -0
  3. data/README.md +269 -79
  4. data/db/migrate/00003_create_file_sources.rb +5 -0
  5. data/db/migrate/00004_create_nodes.rb +17 -0
  6. data/db/migrate/00005_create_tags.rb +7 -0
  7. data/db/migrate/00006_create_node_tags.rb +2 -0
  8. data/db/migrate/00007_create_robot_nodes.rb +7 -0
  9. data/db/schema.sql +41 -29
  10. data/docs/api/yard/HTM/Configuration.md +54 -0
  11. data/docs/api/yard/HTM/Database.md +13 -10
  12. data/docs/api/yard/HTM/EmbeddingService.md +5 -1
  13. data/docs/api/yard/HTM/LongTermMemory.md +18 -277
  14. data/docs/api/yard/HTM/PropositionError.md +18 -0
  15. data/docs/api/yard/HTM/PropositionService.md +66 -0
  16. data/docs/api/yard/HTM/QueryCache.md +88 -0
  17. data/docs/api/yard/HTM/RobotGroup.md +481 -0
  18. data/docs/api/yard/HTM/SqlBuilder.md +108 -0
  19. data/docs/api/yard/HTM/TagService.md +4 -0
  20. data/docs/api/yard/HTM/Telemetry/NullInstrument.md +13 -0
  21. data/docs/api/yard/HTM/Telemetry/NullMeter.md +15 -0
  22. data/docs/api/yard/HTM/Telemetry.md +109 -0
  23. data/docs/api/yard/HTM/WorkingMemoryChannel.md +176 -0
  24. data/docs/api/yard/HTM.md +11 -23
  25. data/docs/api/yard/index.csv +102 -25
  26. data/docs/api/yard-reference.md +8 -0
  27. data/docs/assets/images/multi-provider-failover.svg +51 -0
  28. data/docs/assets/images/robot-group-architecture.svg +65 -0
  29. data/docs/database/README.md +3 -3
  30. data/docs/database/public.file_sources.svg +29 -21
  31. data/docs/database/public.node_tags.md +2 -0
  32. data/docs/database/public.node_tags.svg +53 -41
  33. data/docs/database/public.nodes.md +2 -0
  34. data/docs/database/public.nodes.svg +52 -40
  35. data/docs/database/public.robot_nodes.md +2 -0
  36. data/docs/database/public.robot_nodes.svg +30 -22
  37. data/docs/database/public.robots.svg +16 -12
  38. data/docs/database/public.tags.md +3 -0
  39. data/docs/database/public.tags.svg +41 -33
  40. data/docs/database/schema.json +66 -0
  41. data/docs/database/schema.svg +60 -48
  42. data/docs/development/index.md +13 -0
  43. data/docs/development/rake-tasks.md +1068 -0
  44. data/docs/getting-started/quick-start.md +144 -155
  45. data/docs/guides/adding-memories.md +2 -3
  46. data/docs/guides/context-assembly.md +185 -184
  47. data/docs/guides/getting-started.md +154 -148
  48. data/docs/guides/index.md +7 -0
  49. data/docs/guides/long-term-memory.md +60 -92
  50. data/docs/guides/mcp-server.md +617 -0
  51. data/docs/guides/multi-robot.md +249 -345
  52. data/docs/guides/recalling-memories.md +153 -163
  53. data/docs/guides/robot-groups.md +604 -0
  54. data/docs/guides/search-strategies.md +61 -58
  55. data/docs/guides/working-memory.md +103 -136
  56. data/docs/index.md +30 -26
  57. data/examples/robot_groups/robot_worker.rb +1 -2
  58. data/examples/robot_groups/same_process.rb +1 -4
  59. data/lib/htm/robot_group.rb +721 -0
  60. data/lib/htm/version.rb +1 -1
  61. data/lib/htm/working_memory_channel.rb +250 -0
  62. data/lib/htm.rb +2 -0
  63. data/mkdocs.yml +2 -0
  64. metadata +18 -9
  65. data/db/migrate/00009_add_working_memory_to_robot_nodes.rb +0 -12
  66. data/db/migrate/00010_add_soft_delete_to_associations.rb +0 -29
  67. data/db/migrate/00011_add_performance_indexes.rb +0 -21
  68. data/db/migrate/00012_add_tags_trigram_index.rb +0 -18
  69. data/db/migrate/00013_enable_lz4_compression.rb +0 -43
  70. data/examples/robot_groups/lib/robot_group.rb +0 -419
  71. data/examples/robot_groups/lib/working_memory_channel.rb +0 -140
@@ -51,15 +51,10 @@ htm = HTM.new(
51
51
 
52
52
  ### Adding Memories
53
53
 
54
- When you add a node, it goes to both working and long-term memory:
54
+ When you remember content, it goes to both working and long-term memory:
55
55
 
56
56
  ```ruby
57
- htm.add_node(
58
- "fact_001",
59
- "User prefers Ruby for scripting",
60
- type: :fact,
61
- importance: 7.0
62
- )
57
+ htm.remember("User prefers Ruby for scripting")
63
58
 
64
59
  # Internally:
65
60
  # 1. Calculate token count
@@ -74,8 +69,8 @@ When you recall, memories are added to working memory:
74
69
 
75
70
  ```ruby
76
71
  memories = htm.recall(
77
- timeframe: "last week",
78
- topic: "database design"
72
+ "database design",
73
+ timeframe: "last week"
79
74
  )
80
75
 
81
76
  # Internally:
@@ -123,7 +118,6 @@ class MemoryMonitor
123
118
 
124
119
  def report
125
120
  wm = @htm.working_memory
126
- stats = @htm.memory_stats
127
121
 
128
122
  puts "=== Working Memory Report ==="
129
123
  puts "Capacity: #{wm.max_tokens} tokens"
@@ -134,8 +128,7 @@ class MemoryMonitor
134
128
  puts "Average tokens per node: #{wm.token_count / wm.node_count}" if wm.node_count > 0
135
129
  puts
136
130
  puts "=== Long-term Memory ==="
137
- puts "Total nodes: #{stats[:total_nodes]}"
138
- puts "Database size: #{(stats[:database_size] / 1024.0 / 1024.0).round(2)} MB"
131
+ puts "Total nodes: #{HTM::Models::Node.count}"
139
132
  end
140
133
 
141
134
  def health_check
@@ -189,29 +182,24 @@ htm = HTM.new(
189
182
  working_memory_size: 10_000 # Small for demo
190
183
  )
191
184
 
192
- # Add important fact (will stay)
193
- htm.add_node(
194
- "critical",
185
+ # Add important fact (stays longer due to higher access frequency)
186
+ critical_id = htm.remember(
195
187
  "Critical system password",
196
- importance: 10.0
188
+ metadata: { priority: "critical" }
197
189
  )
198
190
 
199
- # Add many low-importance items
191
+ # Add many items
200
192
  100.times do |i|
201
- htm.add_node(
202
- "temp_#{i}",
203
- "Temporary note #{i}",
204
- importance: 1.0
205
- )
193
+ htm.remember("Temporary note #{i}")
206
194
  end
207
195
 
208
- # Check what survived
196
+ # Check what survived in working memory
209
197
  wm = htm.working_memory
210
198
  puts "Surviving nodes: #{wm.node_count}"
211
199
 
212
- # Critical fact should still be there
213
- critical = htm.retrieve("critical")
214
- puts "Critical fact present: #{!critical.nil?}"
200
+ # Critical fact is still in long-term memory
201
+ critical = htm.long_term_memory.retrieve(critical_id)
202
+ puts "Critical fact present in LTM: #{!critical.nil?}"
215
203
  ```
216
204
 
217
205
  ### Manual Eviction
@@ -235,35 +223,31 @@ end
235
223
 
236
224
  ## Best Practices
237
225
 
238
- ### 1. Set Appropriate Importance
226
+ ### 1. Use Metadata for Priority Tracking
239
227
 
240
228
  ```ruby
241
- # Critical data: Never evict
242
- htm.add_node(
243
- "api_key",
244
- "Production API key",
245
- importance: 10.0
229
+ # Critical data: Mark with priority metadata
230
+ htm.remember(
231
+ "Production API key: secret123",
232
+ metadata: { priority: "critical", category: "credentials" }
246
233
  )
247
234
 
248
- # Important context: Retain longer
249
- htm.add_node(
250
- "user_goal",
235
+ # Important context: Mark appropriately
236
+ htm.remember(
251
237
  "User wants to optimize database",
252
- importance: 8.0
238
+ metadata: { priority: "high", category: "goal" }
253
239
  )
254
240
 
255
- # Temporary context: Evict when needed
256
- htm.add_node(
257
- "current_topic",
241
+ # Temporary context
242
+ htm.remember(
258
243
  "Discussing query optimization",
259
- importance: 5.0
244
+ metadata: { priority: "medium", category: "context" }
260
245
  )
261
246
 
262
- # Disposable notes: Evict first
263
- htm.add_node(
264
- "scratch",
247
+ # Disposable notes
248
+ htm.remember(
265
249
  "Temporary calculation result",
266
- importance: 1.0
250
+ metadata: { priority: "low", category: "scratch" }
267
251
  )
268
252
  ```
269
253
 
@@ -305,16 +289,16 @@ Don't load unnecessary data into working memory:
305
289
  ```ruby
306
290
  # Bad: Load everything
307
291
  all_memories = htm.recall(
292
+ "anything",
308
293
  timeframe: "all time",
309
- topic: "anything",
310
294
  limit: 1000
311
295
  )
312
296
  # This fills working memory with potentially irrelevant data
313
297
 
314
298
  # Good: Load what you need
315
299
  relevant = htm.recall(
300
+ "current project",
316
301
  timeframe: "last week",
317
- topic: "current project",
318
302
  limit: 20
319
303
  )
320
304
  # This keeps working memory focused
@@ -322,25 +306,27 @@ relevant = htm.recall(
322
306
 
323
307
  ### 4. Clean Up When Done
324
308
 
325
- Remove temporary memories:
309
+ Remove temporary memories when no longer needed:
326
310
 
327
311
  ```ruby
328
- def with_temporary_context(htm, key, value)
312
+ def with_temporary_context(htm, value)
329
313
  # Add temporary context
330
- htm.add_node(key, value, type: :context, importance: 2.0)
314
+ node_id = htm.remember(value, metadata: { temporary: true })
331
315
 
332
- yield
316
+ result = yield
333
317
 
334
- # Clean up
335
- htm.forget(key, confirm: :confirmed)
318
+ # Clean up - soft delete by default (recoverable)
319
+ htm.forget(node_id)
320
+
321
+ result
336
322
  end
337
323
 
338
- with_temporary_context(htm, "scratch_001", "Temp data") do
324
+ with_temporary_context(htm, "Temp calculation data") do
339
325
  # Use the temporary context
340
- context = htm.create_context(strategy: :recent)
341
- # ... do work
326
+ context = htm.working_memory.assemble_context(strategy: :recent)
327
+ # ... do work with context
342
328
  end
343
- # Temp data is now removed
329
+ # Temp data is now soft-deleted
344
330
  ```
345
331
 
346
332
  ### 5. Batch Operations Carefully
@@ -348,23 +334,9 @@ end
348
334
  Be mindful when adding many memories at once:
349
335
 
350
336
  ```ruby
351
- # Risky: Might fill working memory quickly
352
- 1000.times do |i|
353
- htm.add_node("item_#{i}", "Data #{i}", importance: 5.0)
354
- end
355
-
356
- # Better: Add with appropriate importance
357
- 1000.times do |i|
358
- htm.add_node(
359
- "item_#{i}",
360
- "Data #{i}",
361
- importance: 3.0 # Lower importance for bulk data
362
- )
363
- end
364
-
365
- # Or: Monitor during batch operations
337
+ # Add batch data with monitoring
366
338
  batch_data.each_with_index do |data, i|
367
- htm.add_node("item_#{i}", data, importance: 5.0)
339
+ htm.remember(data, metadata: { batch: "import_001", index: i })
368
340
 
369
341
  # Check capacity every 100 items
370
342
  if i % 100 == 0
@@ -378,58 +350,56 @@ end
378
350
 
379
351
  ### Strategy 1: Sliding Window
380
352
 
381
- Keep only recent memories:
353
+ Keep only recent memories by tracking node IDs:
382
354
 
383
355
  ```ruby
384
356
  class SlidingWindow
385
357
  def initialize(htm, window_size: 50)
386
358
  @htm = htm
387
359
  @window_size = window_size
388
- @keys = []
360
+ @node_ids = []
389
361
  end
390
362
 
391
- def add(key, value, **opts)
392
- @htm.add_node(key, value, **opts)
393
- @keys << key
363
+ def add(value, **opts)
364
+ node_id = @htm.remember(value, **opts)
365
+ @node_ids << node_id
394
366
 
395
- # Evict oldest if window exceeded
396
- if @keys.length > @window_size
397
- oldest = @keys.shift
398
- @htm.forget(oldest, confirm: :confirmed) rescue nil
367
+ # Forget oldest if window exceeded
368
+ if @node_ids.length > @window_size
369
+ oldest_id = @node_ids.shift
370
+ @htm.forget(oldest_id) rescue nil
399
371
  end
372
+
373
+ node_id
400
374
  end
401
375
  end
402
376
  ```
403
377
 
404
- ### Strategy 2: Importance Thresholding
378
+ ### Strategy 2: Priority-Based Management
405
379
 
406
- Only keep high-importance memories:
380
+ Use metadata to track priority:
407
381
 
408
382
  ```ruby
409
- class ImportanceFilter
410
- def initialize(htm, min_importance: 7.0)
383
+ class PriorityManager
384
+ def initialize(htm)
411
385
  @htm = htm
412
- @min_importance = min_importance
413
386
  end
414
387
 
415
- def add(key, value, importance:, **opts)
416
- @htm.add_node(key, value, importance: importance, **opts)
388
+ def add(value, priority: "medium", **opts)
389
+ metadata = (opts[:metadata] || {}).merge(priority: priority)
390
+ node_id = @htm.remember(value, **opts.merge(metadata: metadata))
417
391
 
418
- # If low importance and memory is tight, evict immediately
419
- if importance < @min_importance &&
420
- @htm.working_memory.utilization_percentage > 80
392
+ # If low priority and memory is tight, it will evict naturally
393
+ # HTM uses LFU + LRU eviction based on access patterns
421
394
 
422
- # Let it evict naturally or remove from working memory
423
- # (Note: HTM doesn't expose direct working memory removal,
424
- # so we rely on natural eviction)
425
- end
395
+ node_id
426
396
  end
427
397
  end
428
398
  ```
429
399
 
430
400
  ### Strategy 3: Topic-Based Management
431
401
 
432
- Group memories by topic and manage separately:
402
+ Group memories by topic using tags:
433
403
 
434
404
  ```ruby
435
405
  class TopicManager
@@ -438,15 +408,17 @@ class TopicManager
438
408
  @topics = Hash.new { |h, k| h[k] = [] }
439
409
  end
440
410
 
441
- def add(key, value, topic:, **opts)
442
- @htm.add_node(key, value, **opts)
443
- @topics[topic] << key
411
+ def add(value, topic:, **opts)
412
+ tags = (opts[:tags] || []) + ["topic:#{topic}"]
413
+ node_id = @htm.remember(value, **opts.merge(tags: tags))
414
+ @topics[topic] << node_id
415
+ node_id
444
416
  end
445
417
 
446
418
  def clear_topic(topic)
447
- keys = @topics[topic] || []
448
- keys.each do |key|
449
- @htm.forget(key, confirm: :confirmed) rescue nil
419
+ node_ids = @topics[topic] || []
420
+ node_ids.each do |node_id|
421
+ @htm.forget(node_id) rescue nil
450
422
  end
451
423
  @topics.delete(topic)
452
424
  end
@@ -471,8 +443,7 @@ medium = "A" * 100 # ~25 tokens
471
443
  long = "word " * 1000 # ~1000 tokens
472
444
 
473
445
  # Check token count of a string
474
- embedding_service = HTM::EmbeddingService.new
475
- tokens = embedding_service.count_tokens(long)
446
+ tokens = HTM.configuration.count_tokens(long)
476
447
  puts "Token count: #{tokens}"
477
448
  ```
478
449
 
@@ -512,18 +483,18 @@ htm = HTM.new(robot_name: "Perf Test")
512
483
 
513
484
  # Add 1000 memories
514
485
  1000.times do |i|
515
- htm.add_node("key_#{i}", "Value #{i}", importance: 5.0)
486
+ htm.remember("Value #{i}")
516
487
  end
517
488
 
518
489
  # Benchmark working memory access
519
490
  Benchmark.bm do |x|
520
- x.report("create_context:") do
521
- 1000.times { htm.create_context(strategy: :balanced) }
491
+ x.report("assemble_context:") do
492
+ 1000.times { htm.working_memory.assemble_context(strategy: :balanced) }
522
493
  end
523
494
  end
524
495
 
525
496
  # Typical results:
526
- # create_context: ~1ms per call
497
+ # assemble_context: ~1ms per call
527
498
  ```
528
499
 
529
500
  ### Optimization Tips
@@ -532,7 +503,7 @@ end
532
503
  # 1. Avoid frequent context assembly
533
504
  # Bad: Assemble context every message
534
505
  def process_message(message)
535
- context = htm.create_context # Slow if called frequently
506
+ context = htm.working_memory.assemble_context(strategy: :balanced) # Slow if called frequently
536
507
  llm.chat(context + message)
537
508
  end
538
509
 
@@ -542,7 +513,7 @@ end
542
513
 
543
514
  def process_message(message)
544
515
  if @context_cache.nil? || @context_age > 10
545
- @context_cache = htm.create_context
516
+ @context_cache = htm.working_memory.assemble_context(strategy: :balanced)
546
517
  @context_age = 0
547
518
  end
548
519
  @context_age += 1
@@ -552,7 +523,7 @@ end
552
523
 
553
524
  # 2. Use appropriate token limits
554
525
  # Don't request more than your LLM can handle
555
- context = htm.create_context(
526
+ context = htm.working_memory.assemble_context(
556
527
  strategy: :balanced,
557
528
  max_tokens: 100_000 # Match LLM's context window
558
529
  )
@@ -605,29 +576,25 @@ end
605
576
  **Issue: Working memory always full**
606
577
 
607
578
  ```ruby
608
- # Check if you're adding too much
609
- stats = htm.memory_stats
610
- wm_util = stats[:working_memory][:utilization]
579
+ # Check working memory utilization
580
+ wm_util = htm.working_memory.utilization_percentage
611
581
 
612
582
  if wm_util > 95
613
583
  puts "Working memory consistently full"
614
584
  puts "Solutions:"
615
- puts "1. Increase working_memory_size"
616
- puts "2. Lower importance of bulk data"
617
- puts "3. Reduce recall limit"
618
- puts "4. Clean up temporary data more frequently"
585
+ puts "1. Increase working_memory_size when creating HTM"
586
+ puts "2. Reduce recall limit"
587
+ puts "3. Clean up temporary data more frequently with forget()"
619
588
  end
620
589
  ```
621
590
 
622
591
  **Issue: Important data getting evicted**
623
592
 
624
593
  ```ruby
625
- # Increase importance of critical data
626
- htm.add_node(
627
- "critical_data",
628
- "Important information",
629
- importance: 9.5 # High enough to avoid eviction
630
- )
594
+ # HTM evicts based on access frequency and recency
595
+ # Access important data more frequently to keep it in working memory
596
+ # Or query it from long-term memory when needed:
597
+ critical = htm.long_term_memory.retrieve(critical_node_id)
631
598
  ```
632
599
 
633
600
  **Issue: Memory utilization too low**
@@ -640,8 +607,8 @@ if wm_util < 20
640
607
  puts "Working memory underutilized"
641
608
  puts "Consider:"
642
609
  puts "1. Reducing working_memory_size to save RAM"
643
- puts "2. Recalling more context"
644
- puts "3. Using larger token limits in create_context"
610
+ puts "2. Recalling more context with larger limit"
611
+ puts "3. Using larger token limits in assemble_context"
645
612
  end
646
613
  ```
647
614
 
@@ -678,37 +645,37 @@ end
678
645
 
679
646
  monitor = Monitor.new(htm)
680
647
 
681
- # Add memories with different importance
648
+ # Add memories with different priorities via metadata
682
649
  puts "Adding critical data..."
683
- htm.add_node("critical", "Critical system data", importance: 10.0)
650
+ critical_id = htm.remember("Critical system data", metadata: { priority: "critical" })
684
651
  monitor.report
685
652
 
686
653
  puts "\nAdding important data..."
687
654
  10.times do |i|
688
- htm.add_node("important_#{i}", "Important item #{i}", importance: 8.0)
655
+ htm.remember("Important item #{i}", metadata: { priority: "high" })
689
656
  end
690
657
  monitor.report
691
658
 
692
659
  puts "\nAdding regular data..."
693
660
  50.times do |i|
694
- htm.add_node("regular_#{i}", "Regular item #{i}", importance: 5.0)
661
+ htm.remember("Regular item #{i}", metadata: { priority: "medium" })
695
662
  end
696
663
  monitor.report
697
664
 
698
665
  puts "\nAdding temporary data..."
699
666
  100.times do |i|
700
- htm.add_node("temp_#{i}", "Temporary item #{i}", importance: 2.0)
667
+ htm.remember("Temporary item #{i}", metadata: { priority: "low" })
701
668
  end
702
669
  monitor.report
703
670
 
704
- # Check what survived
671
+ # Check that critical data is still in long-term memory
705
672
  puts "\n=== Survival Check ==="
706
- critical = htm.retrieve("critical")
707
- puts "Critical survived: #{!critical.nil?}"
673
+ critical = htm.long_term_memory.retrieve(critical_id)
674
+ puts "Critical in LTM: #{!critical.nil?}"
708
675
 
709
- # Create context
676
+ # Create context from working memory
710
677
  puts "\nCreating context..."
711
- context = htm.create_context(strategy: :important, max_tokens: 50_000)
678
+ context = htm.working_memory.assemble_context(strategy: :balanced, max_tokens: 50_000)
712
679
  puts "Context length: #{context.length} characters"
713
680
 
714
681
  # Final stats
data/docs/index.md CHANGED
@@ -1,12 +1,12 @@
1
1
 
2
2
  <div align="center">
3
- <div style="background: linear-gradient(135deg, #ff6b6b 0%, #ee5a6f 100%); border: 4px solid #ff0000; border-radius: 12px; padding: 20px; margin: 20px auto; max-width: 800px; box-shadow: 0 8px 16px rgba(255, 0, 0, 0.3);">
4
- <p style="color: #ffffff; font-size: 24px; font-weight: bold; margin: 0; text-shadow: 2px 2px 4px rgba(0,0,0,0.5);">
5
- ⚠️ WARNING ⚠️
3
+ <div style="background: linear-gradient(135deg, #ffd93d 0%, #f5c800 100%); border: 4px solid #e6b800; border-radius: 12px; padding: 20px; margin: 20px auto; max-width: 800px; box-shadow: 0 8px 16px rgba(230, 184, 0, 0.3);">
4
+ <p style="color: #000000; font-size: 42px; font-weight: bold; margin: 0;">
5
+ 💣 CAUTION 💣
6
6
  </p>
7
- <p style="color: #fff; font-size: 16px; margin: 10px 0 0 0; line-height: 1.6;">
8
- This documentation is AI-generated and may contain <strong>hallucinations</strong>, <strong>inaccuracies</strong>, or <strong>outdated information</strong>.<br/>
9
- Always verify critical details in the source code.
7
+ <p style="color: #000; font-size: 27px; font-weight: bold; margin: 10px 0 0 0; line-height: 1.6;">
8
+ This documentation may contain <strong>inaccuracies</strong>.<br/>
9
+ Verify critical details in the source code and example demos.
10
10
  </p>
11
11
  </div>
12
12
 
@@ -63,14 +63,14 @@ HTM enables multiple AI robots to share a collective memory:
63
63
  - Cross-robot context awareness and conversation continuity
64
64
  - Query conversation timelines across multiple robots
65
65
 
66
- ### Knowledge Graph
66
+ ### Pseudo Knowledge Graph
67
67
 
68
- Build rich relationship networks between memories:
68
+ Build rich relationship networks between memories using a hierarchical taxonomy:
69
69
 
70
70
  - Link related memories together
71
- - Tag-based categorization
71
+ - Tag-based categorization with up to four levels of abstraction
72
72
  - Importance scoring for prioritization
73
- - Navigate memory relationships programmatically
73
+ - Navigate memory relationship abstractions
74
74
 
75
75
  ## Quick Example
76
76
 
@@ -79,33 +79,36 @@ Here's how simple it is to get started with HTM:
79
79
  ```ruby
80
80
  require 'htm'
81
81
 
82
+ # Configure HTM globally (optional - uses Ollama by default)
83
+ HTM.configure do |config|
84
+ config.embedding_provider = :ollama
85
+ config.embedding_model = 'nomic-embed-text:latest'
86
+ config.tag_provider = :ollama
87
+ config.tag_model = 'gemma3:latest'
88
+ end
89
+
82
90
  # Initialize HTM for your robot
83
91
  htm = HTM.new(
84
- robot_name: "Code Helper",
85
- working_memory_size: 128_000, # 128k tokens
86
- embedding_service: :ollama, # Use Ollama for embeddings
87
- embedding_model: 'gpt-oss' # Default embedding model
92
+ robot_name: "Chat Assistant",
93
+ working_memory_size: 128_000 # 128k tokens
88
94
  )
89
95
 
90
- # Add memories (embeddings generated automatically)
91
- htm.add_node(
92
- "decision_001",
96
+ # Remember information (embeddings generated automatically in background)
97
+ node_id = htm.remember(
93
98
  "We decided to use PostgreSQL for HTM storage",
94
- type: :decision,
95
- category: "architecture",
96
- importance: 9.0,
97
- tags: ["database", "architecture"]
99
+ tags: ["database:postgresql", "architecture"],
100
+ metadata: { category: "architecture", priority: "high" }
98
101
  )
99
102
 
100
103
  # Recall memories from the past
101
104
  memories = htm.recall(
105
+ "database decisions", # Topic (first positional argument)
102
106
  timeframe: "last week",
103
- topic: "database decisions",
104
107
  strategy: :hybrid
105
108
  )
106
109
 
107
- # Create context for your LLM
108
- context = htm.create_context(
110
+ # Create context for your LLM from working memory
111
+ context = htm.working_memory.assemble_context(
109
112
  strategy: :balanced,
110
113
  max_tokens: 50_000
111
114
  )
@@ -117,8 +120,9 @@ response = llm.chat(
117
120
  user: "What database did we decide to use?"
118
121
  )
119
122
 
120
- # Explicit deletion only when needed
121
- htm.forget("old_decision", confirm: :confirmed)
123
+ # Explicit deletion only when needed (soft delete by default)
124
+ htm.forget(node_id) # Soft delete (recoverable)
125
+ htm.forget(node_id, soft: false, confirm: :confirmed) # Permanent delete
122
126
  ```
123
127
 
124
128
  ## Use Cases
@@ -20,7 +20,6 @@
20
20
  require 'logger'
21
21
  require 'json'
22
22
  require_relative '../../lib/htm'
23
- require_relative 'lib/working_memory_channel'
24
23
 
25
24
  robot_name = ARGV[0]
26
25
  group_name = ARGV[1]
@@ -53,7 +52,7 @@ htm = HTM.new(robot_name: robot_name, working_memory_size: 8000)
53
52
  db_config = HTM::Database.default_config
54
53
 
55
54
  # Setup channel for cross-process notifications
56
- channel = WorkingMemoryChannel.new(group_name, db_config)
55
+ channel = HTM::WorkingMemoryChannel.new(group_name, db_config)
57
56
 
58
57
  # Track notifications received
59
58
  notifications_count = 0
@@ -26,9 +26,6 @@
26
26
  require_relative '../../lib/htm'
27
27
  require 'json'
28
28
 
29
- require_relative 'lib/working_memory_channel'
30
- require_relative 'lib/robot_group'
31
-
32
29
  # =============================================================================
33
30
  # Demo Script
34
31
  # =============================================================================
@@ -59,7 +56,7 @@ begin
59
56
  # ---------------------------------------------------------------------------
60
57
  puts "\n2. Creating robot group with primary + standby..."
61
58
 
62
- group = RobotGroup.new(
59
+ group = HTM::RobotGroup.new(
63
60
  name: 'customer-support-ha',
64
61
  active: ['support-primary'],
65
62
  passive: ['support-standby'],