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
@@ -0,0 +1,665 @@
1
+ # WorkingMemory Class
2
+
3
+ Token-limited active context for immediate LLM use.
4
+
5
+ ## Overview
6
+
7
+ `HTM::WorkingMemory` manages the active conversation context within strict token limits. When capacity is reached, it intelligently evicts less important or older nodes back to long-term storage.
8
+
9
+ **Key Features:**
10
+
11
+ - Token-based capacity management
12
+ - LRU (Least Recently Used) tracking
13
+ - Importance-weighted eviction
14
+ - Multiple context assembly strategies
15
+ - Real-time utilization monitoring
16
+
17
+ ## Class Definition
18
+
19
+ ```ruby
20
+ class HTM::WorkingMemory
21
+ attr_reader :max_tokens
22
+ end
23
+ ```
24
+
25
+ ## Initialization
26
+
27
+ ### `new(max_tokens:)` {: #new }
28
+
29
+ Create a new working memory instance.
30
+
31
+ ```ruby
32
+ HTM::WorkingMemory.new(max_tokens: 128_000)
33
+ ```
34
+
35
+ #### Parameters
36
+
37
+ | Parameter | Type | Default | Description |
38
+ |-----------|------|---------|-------------|
39
+ | `max_tokens` | Integer | *required* | Maximum tokens allowed in working memory |
40
+
41
+ #### Returns
42
+
43
+ - `HTM::WorkingMemory` instance
44
+
45
+ #### Examples
46
+
47
+ ```ruby
48
+ # Standard working memory (128K tokens)
49
+ wm = HTM::WorkingMemory.new(max_tokens: 128_000)
50
+
51
+ # Large context window (256K tokens)
52
+ wm = HTM::WorkingMemory.new(max_tokens: 256_000)
53
+
54
+ # Small working memory (32K tokens)
55
+ wm = HTM::WorkingMemory.new(max_tokens: 32_000)
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Instance Attributes
61
+
62
+ ### `max_tokens` {: #max_tokens }
63
+
64
+ Maximum token capacity for this working memory.
65
+
66
+ - **Type**: Integer
67
+ - **Read-only**: Yes
68
+
69
+ ```ruby
70
+ wm.max_tokens # => 128000
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Public Methods
76
+
77
+ ### `add(key, value, **options)` {: #add }
78
+
79
+ Add a node to working memory.
80
+
81
+ ```ruby
82
+ add(key, value,
83
+ token_count:,
84
+ importance: 1.0,
85
+ from_recall: false
86
+ )
87
+ ```
88
+
89
+ #### Parameters
90
+
91
+ | Parameter | Type | Default | Description |
92
+ |-----------|------|---------|-------------|
93
+ | `key` | String | *required* | Node identifier |
94
+ | `value` | String | *required* | Node content |
95
+ | `token_count` | Integer | *required* | Number of tokens in this node |
96
+ | `importance` | Float | `1.0` | Importance score (0.0-10.0) |
97
+ | `from_recall` | Boolean | `false` | Whether this node was recalled from long-term memory |
98
+
99
+ #### Returns
100
+
101
+ - `void`
102
+
103
+ #### Side Effects
104
+
105
+ - Adds node to internal hash
106
+ - Updates access order (LRU tracking)
107
+ - Records timestamp
108
+
109
+ #### Examples
110
+
111
+ ```ruby
112
+ # Add a simple node
113
+ wm.add("fact_001", "PostgreSQL is our database",
114
+ token_count: 50,
115
+ importance: 7.0
116
+ )
117
+
118
+ # Add recalled node
119
+ wm.add("decision_001", "Use microservices architecture",
120
+ token_count: 120,
121
+ importance: 9.0,
122
+ from_recall: true
123
+ )
124
+
125
+ # Add low-importance temporary note
126
+ wm.add("temp_note", "Check deployment at 3pm",
127
+ token_count: 30,
128
+ importance: 2.0
129
+ )
130
+ ```
131
+
132
+ #### Notes
133
+
134
+ - Does **not** check capacity - use `has_space?` first
135
+ - Updates existing node if key already exists
136
+ - Automatically updates access order for LRU
137
+
138
+ ---
139
+
140
+ ### `remove(key)` {: #remove }
141
+
142
+ Remove a node from working memory.
143
+
144
+ ```ruby
145
+ remove(key)
146
+ ```
147
+
148
+ #### Parameters
149
+
150
+ | Parameter | Type | Description |
151
+ |-----------|------|-------------|
152
+ | `key` | String | Node identifier |
153
+
154
+ #### Returns
155
+
156
+ - `void`
157
+
158
+ #### Side Effects
159
+
160
+ - Removes node from internal hash
161
+ - Removes from access order tracking
162
+
163
+ #### Examples
164
+
165
+ ```ruby
166
+ # Remove a node
167
+ wm.remove("temp_note_123")
168
+
169
+ # Safe removal (checks existence)
170
+ if wm.respond_to?(:has_key?) && wm.has_key?("old_key")
171
+ wm.remove("old_key")
172
+ end
173
+ ```
174
+
175
+ ---
176
+
177
+ ### `has_space?(token_count)` {: #has_space }
178
+
179
+ Check if there's space for a node.
180
+
181
+ ```ruby
182
+ has_space?(token_count)
183
+ ```
184
+
185
+ #### Parameters
186
+
187
+ | Parameter | Type | Description |
188
+ |-----------|------|-------------|
189
+ | `token_count` | Integer | Number of tokens needed |
190
+
191
+ #### Returns
192
+
193
+ - `Boolean` - `true` if space available, `false` otherwise
194
+
195
+ #### Examples
196
+
197
+ ```ruby
198
+ # Check before adding
199
+ if wm.has_space?(500)
200
+ wm.add("new_node", "content...", token_count: 500)
201
+ else
202
+ puts "Working memory full, need to evict"
203
+ end
204
+
205
+ # Check capacity for large addition
206
+ large_content_tokens = 5000
207
+ if wm.has_space?(large_content_tokens)
208
+ wm.add("large_node", large_content, token_count: large_content_tokens)
209
+ else
210
+ # Evict to make space
211
+ evicted = wm.evict_to_make_space(large_content_tokens)
212
+ wm.add("large_node", large_content, token_count: large_content_tokens)
213
+ end
214
+ ```
215
+
216
+ ---
217
+
218
+ ### `evict_to_make_space(needed_tokens)` {: #evict_to_make_space }
219
+
220
+ Evict nodes to free up space for new content.
221
+
222
+ ```ruby
223
+ evict_to_make_space(needed_tokens)
224
+ ```
225
+
226
+ #### Parameters
227
+
228
+ | Parameter | Type | Description |
229
+ |-----------|------|-------------|
230
+ | `needed_tokens` | Integer | Number of tokens needed |
231
+
232
+ #### Returns
233
+
234
+ - `Array<Hash>` - Evicted nodes
235
+
236
+ Each hash contains:
237
+
238
+ ```ruby
239
+ {
240
+ key: "node_key",
241
+ value: "node content..."
242
+ }
243
+ ```
244
+
245
+ #### Eviction Strategy
246
+
247
+ Nodes are sorted by:
248
+
249
+ 1. **Importance** (ascending) - Lower importance evicted first
250
+ 2. **Recency** (descending) - Older nodes evicted first
251
+
252
+ Formula: `[importance, -recency_in_seconds]`
253
+
254
+ #### Side Effects
255
+
256
+ - Removes evicted nodes from working memory
257
+ - Updates access order tracking
258
+
259
+ #### Examples
260
+
261
+ ```ruby
262
+ # Make space for 10,000 tokens
263
+ evicted = wm.evict_to_make_space(10_000)
264
+
265
+ puts "Evicted #{evicted.length} nodes:"
266
+ evicted.each do |node|
267
+ puts " - #{node[:key]}"
268
+ end
269
+
270
+ # Make space and log to long-term memory
271
+ evicted = wm.evict_to_make_space(needed_tokens)
272
+ evicted_keys = evicted.map { |n| n[:key] }
273
+ long_term_memory.mark_evicted(evicted_keys)
274
+
275
+ # Check how much was freed
276
+ tokens_freed = evicted.sum { |n| n[:token_count] }
277
+ puts "Freed #{tokens_freed} tokens"
278
+ ```
279
+
280
+ #### Notes
281
+
282
+ - Evicts just enough to meet `needed_tokens`
283
+ - May evict more than one node
284
+ - Preserves high-importance and recent nodes
285
+
286
+ ---
287
+
288
+ ### `assemble_context(strategy:, max_tokens:)` {: #assemble_context }
289
+
290
+ Assemble context string for LLM consumption.
291
+
292
+ ```ruby
293
+ assemble_context(strategy:, max_tokens: nil)
294
+ ```
295
+
296
+ #### Parameters
297
+
298
+ | Parameter | Type | Default | Description |
299
+ |-----------|------|---------|-------------|
300
+ | `strategy` | Symbol | *required* | Assembly strategy (`:recent`, `:important`, `:balanced`) |
301
+ | `max_tokens` | Integer, nil | `@max_tokens` | Optional token limit |
302
+
303
+ #### Assembly Strategies
304
+
305
+ **`:recent`** - Most recently accessed first
306
+
307
+ ```ruby
308
+ # Ordered by access time (newest first)
309
+ # Good for: Conversational continuity
310
+ ```
311
+
312
+ **`:important`** - Highest importance scores first
313
+
314
+ ```ruby
315
+ # Ordered by importance score (highest first)
316
+ # Good for: Critical information prioritization
317
+ ```
318
+
319
+ **`:balanced`** - Weighted by importance and recency
320
+
321
+ ```ruby
322
+ # Formula: importance × (1.0 / (1 + age_in_hours))
323
+ # Good for: General-purpose use (recommended)
324
+ ```
325
+
326
+ #### Returns
327
+
328
+ - `String` - Assembled context with nodes separated by `"\n\n"`
329
+
330
+ #### Examples
331
+
332
+ ```ruby
333
+ # Balanced context (recommended)
334
+ context = wm.assemble_context(strategy: :balanced)
335
+
336
+ # Recent conversations only
337
+ context = wm.assemble_context(strategy: :recent)
338
+
339
+ # Most important information
340
+ context = wm.assemble_context(strategy: :important)
341
+
342
+ # Limited tokens
343
+ context = wm.assemble_context(
344
+ strategy: :balanced,
345
+ max_tokens: 50_000
346
+ )
347
+
348
+ # Use in LLM prompt
349
+ prompt = <<~PROMPT
350
+ Context:
351
+ #{context}
352
+
353
+ Question: #{user_question}
354
+ PROMPT
355
+ ```
356
+
357
+ #### Balanced Strategy Details
358
+
359
+ The balanced strategy uses a decay function:
360
+
361
+ ```ruby
362
+ score = importance × (1.0 / (1 + recency_in_hours))
363
+ ```
364
+
365
+ Examples:
366
+
367
+ | Importance | Age | Score |
368
+ |------------|-----|-------|
369
+ | 10.0 | 1 hour | 5.0 |
370
+ | 10.0 | 5 hours | 1.67 |
371
+ | 5.0 | 1 hour | 2.5 |
372
+ | 5.0 | 5 hours | 0.83 |
373
+
374
+ ---
375
+
376
+ ### `token_count()` {: #token_count }
377
+
378
+ Get current total tokens in working memory.
379
+
380
+ ```ruby
381
+ token_count()
382
+ ```
383
+
384
+ #### Returns
385
+
386
+ - `Integer` - Total tokens across all nodes
387
+
388
+ #### Examples
389
+
390
+ ```ruby
391
+ current = wm.token_count
392
+ puts "Using #{current} tokens"
393
+
394
+ # Check if near capacity
395
+ if wm.token_count > wm.max_tokens * 0.9
396
+ puts "Warning: Working memory 90% full"
397
+ end
398
+
399
+ # Calculate available space
400
+ available = wm.max_tokens - wm.token_count
401
+ puts "#{available} tokens available"
402
+ ```
403
+
404
+ ---
405
+
406
+ ### `utilization_percentage()` {: #utilization_percentage }
407
+
408
+ Get working memory utilization as a percentage.
409
+
410
+ ```ruby
411
+ utilization_percentage()
412
+ ```
413
+
414
+ #### Returns
415
+
416
+ - `Float` - Percentage of capacity used (0.0-100.0, rounded to 2 decimals)
417
+
418
+ #### Examples
419
+
420
+ ```ruby
421
+ util = wm.utilization_percentage
422
+ puts "Working memory: #{util}% full"
423
+
424
+ # Capacity warnings
425
+ case util
426
+ when 0..50
427
+ puts "Plenty of space"
428
+ when 51..80
429
+ puts "Getting full"
430
+ when 81..95
431
+ puts "Warning: High utilization"
432
+ else
433
+ puts "Critical: Near capacity"
434
+ end
435
+
436
+ # Progress bar
437
+ bar_length = (util / 2).round
438
+ bar = "█" * bar_length + "░" * (50 - bar_length)
439
+ puts "[#{bar}] #{util}%"
440
+ ```
441
+
442
+ ---
443
+
444
+ ### `node_count()` {: #node_count }
445
+
446
+ Get the number of nodes in working memory.
447
+
448
+ ```ruby
449
+ node_count()
450
+ ```
451
+
452
+ #### Returns
453
+
454
+ - `Integer` - Number of nodes currently stored
455
+
456
+ #### Examples
457
+
458
+ ```ruby
459
+ count = wm.node_count
460
+ puts "#{count} nodes in working memory"
461
+
462
+ # Average tokens per node
463
+ if count > 0
464
+ avg = wm.token_count / count
465
+ puts "Average: #{avg} tokens per node"
466
+ end
467
+
468
+ # Density check
469
+ if wm.node_count > 100
470
+ puts "Warning: Many small nodes, consider consolidation"
471
+ end
472
+ ```
473
+
474
+ ---
475
+
476
+ ## Usage Patterns
477
+
478
+ ### Capacity Management
479
+
480
+ ```ruby
481
+ # Check capacity before operations
482
+ def add_with_eviction(wm, ltm, key, value, token_count, importance)
483
+ unless wm.has_space?(token_count)
484
+ # Evict and mark in long-term memory
485
+ evicted = wm.evict_to_make_space(token_count)
486
+ evicted_keys = evicted.map { |n| n[:key] }
487
+ ltm.mark_evicted(evicted_keys) unless evicted_keys.empty?
488
+ end
489
+
490
+ wm.add(key, value,
491
+ token_count: token_count,
492
+ importance: importance
493
+ )
494
+ end
495
+ ```
496
+
497
+ ### Monitoring
498
+
499
+ ```ruby
500
+ # Working memory dashboard
501
+ def print_wm_status(wm)
502
+ puts "Working Memory Status:"
503
+ puts " Nodes: #{wm.node_count}"
504
+ puts " Tokens: #{wm.token_count} / #{wm.max_tokens}"
505
+ puts " Utilization: #{wm.utilization_percentage}%"
506
+
507
+ available = wm.max_tokens - wm.token_count
508
+ puts " Available: #{available} tokens"
509
+ end
510
+ ```
511
+
512
+ ### Strategic Context Assembly
513
+
514
+ ```ruby
515
+ # Different contexts for different tasks
516
+ class ContextManager
517
+ def initialize(wm)
518
+ @wm = wm
519
+ end
520
+
521
+ def for_conversation
522
+ # Recent context for chat continuity
523
+ @wm.assemble_context(strategy: :recent, max_tokens: 8000)
524
+ end
525
+
526
+ def for_analysis
527
+ # Important context for deep analysis
528
+ @wm.assemble_context(strategy: :important, max_tokens: 32000)
529
+ end
530
+
531
+ def for_general_task
532
+ # Balanced for most tasks
533
+ @wm.assemble_context(strategy: :balanced)
534
+ end
535
+ end
536
+ ```
537
+
538
+ ### Importance-Based Retention
539
+
540
+ ```ruby
541
+ # Critical memories persist longer
542
+ wm.add("critical_security_alert",
543
+ "SQL injection vulnerability found in user input",
544
+ token_count: 150,
545
+ importance: 10.0 # Maximum importance
546
+ )
547
+
548
+ # Temporary notes evicted first
549
+ wm.add("temp_reminder",
550
+ "Check logs after deployment",
551
+ token_count: 50,
552
+ importance: 1.0 # Minimum importance
553
+ )
554
+ ```
555
+
556
+ ## Performance Characteristics
557
+
558
+ ### Time Complexity
559
+
560
+ | Operation | Complexity | Notes |
561
+ |-----------|------------|-------|
562
+ | `add` | O(1) | Hash insertion + array append |
563
+ | `remove` | O(n) | Array deletion requires scan |
564
+ | `has_space?` | O(n) | Sums all token counts |
565
+ | `evict_to_make_space` | O(n log n) | Sorting nodes |
566
+ | `assemble_context` | O(n log n) | Sorting + concatenation |
567
+ | `token_count` | O(n) | Sums all nodes |
568
+ | `node_count` | O(1) | Hash size |
569
+
570
+ ### Space Complexity
571
+
572
+ - O(n) where n is the number of nodes
573
+ - Each node stores: key, value, token_count, importance, timestamp, from_recall flag
574
+
575
+ ### Optimization Tips
576
+
577
+ 1. **Batch Operations**: Add multiple nodes before checking space
578
+ 2. **Importance Scoring**: Use meaningful scores (1-10) for effective eviction
579
+ 3. **Token Limits**: Set `max_tokens` based on your LLM's context window
580
+ 4. **Strategy Selection**: Use `:recent` for speed, `:balanced` for quality
581
+
582
+ ## Internal Data Structures
583
+
584
+ ### Node Storage
585
+
586
+ ```ruby
587
+ @nodes = {
588
+ "key1" => {
589
+ value: "content...",
590
+ token_count: 150,
591
+ importance: 7.0,
592
+ added_at: Time.now,
593
+ from_recall: false
594
+ },
595
+ "key2" => { ... }
596
+ }
597
+ ```
598
+
599
+ ### Access Order
600
+
601
+ ```ruby
602
+ @access_order = ["key1", "key3", "key2"]
603
+ # Most recently accessed at the end
604
+ ```
605
+
606
+ ## Best Practices
607
+
608
+ ### 1. Check Space Before Adding
609
+
610
+ ```ruby
611
+ # Good
612
+ if wm.has_space?(tokens)
613
+ wm.add(key, value, token_count: tokens)
614
+ else
615
+ wm.evict_to_make_space(tokens)
616
+ wm.add(key, value, token_count: tokens)
617
+ end
618
+
619
+ # Bad - may exceed capacity
620
+ wm.add(key, value, token_count: tokens)
621
+ ```
622
+
623
+ ### 2. Use Appropriate Importance Scores
624
+
625
+ ```ruby
626
+ # Critical architectural decisions
627
+ importance: 10.0
628
+
629
+ # Important facts
630
+ importance: 7.0-8.0
631
+
632
+ # Normal information
633
+ importance: 4.0-6.0
634
+
635
+ # Temporary notes
636
+ importance: 1.0-3.0
637
+ ```
638
+
639
+ ### 3. Monitor Utilization
640
+
641
+ ```ruby
642
+ # Set up alerts
643
+ if wm.utilization_percentage > 90
644
+ warn "Working memory critically full"
645
+ end
646
+ ```
647
+
648
+ ### 4. Choose Right Strategy
649
+
650
+ ```ruby
651
+ # For chat/conversation
652
+ context = wm.assemble_context(strategy: :recent)
653
+
654
+ # For analysis/reasoning
655
+ context = wm.assemble_context(strategy: :important)
656
+
657
+ # For general use
658
+ context = wm.assemble_context(strategy: :balanced)
659
+ ```
660
+
661
+ ## See Also
662
+
663
+ - [HTM API](htm.md) - Main class that uses WorkingMemory
664
+ - [LongTermMemory API](long-term-memory.md) - Persistent storage for evicted nodes
665
+ - [EmbeddingService API](embedding-service.md) - Token counting