htm 0.0.31 → 0.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.irbrc +2 -3
- data/.rubocop.yml +184 -0
- data/CHANGELOG.md +46 -0
- data/README.md +2 -0
- data/Rakefile +93 -12
- data/db/migrate/00008_create_node_relationships.rb +54 -0
- data/db/migrate/00009_fix_node_relationships_column_types.rb +17 -0
- data/db/schema.sql +124 -1
- data/docs/api/database.md +35 -57
- data/docs/api/embedding-service.md +1 -1
- data/docs/api/index.md +26 -15
- data/docs/api/working-memory.md +8 -8
- data/docs/architecture/index.md +5 -7
- data/docs/architecture/overview.md +5 -8
- data/docs/assets/images/htm-architecture-overview.svg +1 -1
- data/docs/assets/images/htm-context-assembly-flow.svg +2 -2
- data/docs/assets/images/htm-layered-architecture.svg +3 -3
- data/docs/assets/images/two-tier-memory-architecture.svg +1 -1
- data/docs/database/README.md +1 -0
- data/docs/database_rake_tasks.md +20 -28
- data/docs/development/contributing.md +5 -5
- data/docs/development/index.md +4 -7
- data/docs/development/schema.md +71 -1
- data/docs/development/setup.md +40 -82
- data/docs/development/testing.md +1 -1
- data/docs/examples/file-loading.md +4 -4
- data/docs/examples/mcp-client.md +1 -1
- data/docs/getting-started/quick-start.md +4 -4
- data/docs/guides/adding-memories.md +14 -1
- data/docs/guides/configuration.md +5 -5
- data/docs/guides/context-assembly.md +4 -4
- data/docs/guides/file-loading.md +12 -12
- data/docs/guides/getting-started.md +2 -2
- data/docs/guides/long-term-memory.md +7 -27
- data/docs/guides/propositions.md +20 -19
- data/docs/guides/recalling-memories.md +5 -5
- data/docs/guides/tags.md +18 -13
- data/docs/multi_framework_support.md +1 -1
- data/docs/robots/hive-mind.md +1 -1
- data/docs/robots/multi-robot.md +2 -2
- data/docs/robots/robot-groups.md +1 -1
- data/docs/robots/two-tier-memory.md +72 -94
- data/docs/setup_local_database.md +8 -54
- data/docs/using_rake_tasks_in_your_app.md +6 -6
- data/examples/01_basic_usage.rb +1 -0
- data/examples/03_custom_llm_configuration.rb +1 -0
- data/examples/04_file_loader_usage.rb +1 -0
- data/examples/05_timeframe_demo.rb +1 -0
- data/examples/06_example_app/app.rb +1 -0
- data/examples/07_cli_app/htm_cli.rb +1 -0
- data/examples/09_mcp_client.rb +1 -0
- data/examples/10_telemetry/demo.rb +1 -0
- data/examples/11_robot_groups/multi_process.rb +1 -0
- data/examples/11_robot_groups/same_process.rb +1 -0
- data/examples/12_rails_app/.envrc +12 -0
- data/examples/12_rails_app/Gemfile +8 -3
- data/examples/12_rails_app/Gemfile.lock +94 -89
- data/examples/12_rails_app/README.md +70 -19
- data/examples/12_rails_app/app/controllers/application_controller.rb +6 -0
- data/examples/12_rails_app/app/controllers/chats_controller.rb +305 -0
- data/examples/12_rails_app/app/controllers/dashboard_controller.rb +3 -0
- data/examples/12_rails_app/app/controllers/files_controller.rb +17 -2
- data/examples/12_rails_app/app/controllers/home_controller.rb +8 -0
- data/examples/12_rails_app/app/controllers/memories_controller.rb +9 -4
- data/examples/12_rails_app/app/controllers/messages_controller.rb +214 -0
- data/examples/12_rails_app/app/controllers/robots_controller.rb +11 -1
- data/examples/12_rails_app/app/controllers/tags_controller.rb +14 -1
- data/examples/12_rails_app/app/javascript/application.js +1 -1
- data/examples/12_rails_app/app/models/application_record.rb +5 -0
- data/examples/12_rails_app/app/models/chat.rb +36 -0
- data/examples/12_rails_app/app/models/message.rb +5 -0
- data/examples/12_rails_app/app/models/model.rb +5 -0
- data/examples/12_rails_app/app/models/tool_call.rb +5 -0
- data/examples/12_rails_app/app/views/chats/index.html.erb +61 -0
- data/examples/12_rails_app/app/views/chats/show.html.erb +213 -0
- data/examples/12_rails_app/app/views/dashboard/index.html.erb +3 -0
- data/examples/12_rails_app/app/views/files/index.html.erb +10 -5
- data/examples/12_rails_app/app/views/files/new.html.erb +4 -2
- data/examples/12_rails_app/app/views/files/show.html.erb +19 -3
- data/examples/12_rails_app/app/views/home/index.html.erb +45 -0
- data/examples/12_rails_app/app/views/layouts/application.html.erb +20 -18
- data/examples/12_rails_app/app/views/memories/_memory_card.html.erb +1 -1
- data/examples/12_rails_app/app/views/memories/deleted.html.erb +3 -1
- data/examples/12_rails_app/app/views/memories/edit.html.erb +2 -0
- data/examples/12_rails_app/app/views/memories/index.html.erb +2 -0
- data/examples/12_rails_app/app/views/memories/new.html.erb +2 -0
- data/examples/12_rails_app/app/views/memories/show.html.erb +4 -2
- data/examples/12_rails_app/app/views/messages/_message.html.erb +20 -0
- data/examples/12_rails_app/app/views/robots/index.html.erb +2 -0
- data/examples/12_rails_app/app/views/robots/new.html.erb +2 -0
- data/examples/12_rails_app/app/views/robots/show.html.erb +2 -0
- data/examples/12_rails_app/app/views/search/index.html.erb +59 -8
- data/examples/12_rails_app/app/views/shared/_navbar.html.erb +75 -29
- data/examples/12_rails_app/app/views/tags/index.html.erb +2 -0
- data/examples/12_rails_app/app/views/tags/show.html.erb +3 -1
- data/examples/12_rails_app/config/application.rb +1 -1
- data/examples/12_rails_app/config/database.yml +9 -5
- data/examples/12_rails_app/config/importmap.rb +1 -1
- data/examples/12_rails_app/config/initializers/htm.rb +9 -2
- data/examples/12_rails_app/config/initializers/ruby_llm.rb +33 -0
- data/examples/12_rails_app/config/routes.rb +39 -23
- data/examples/12_rails_app/db/migrate/20250124000001_create_ruby_llm_tables.rb +34 -0
- data/examples/12_rails_app/db/migrate/20250124000002_create_models_table.rb +28 -0
- data/examples/12_rails_app/db/schema.rb +67 -0
- data/examples/examples_helper.rb +25 -0
- data/lib/htm/circuit_breaker.rb +5 -6
- data/lib/htm/config/builder.rb +12 -12
- data/lib/htm/config/database.rb +21 -27
- data/lib/htm/config/validator.rb +12 -18
- data/lib/htm/config.rb +76 -65
- data/lib/htm/database.rb +193 -199
- data/lib/htm/embedding_service.rb +4 -9
- data/lib/htm/integrations/sinatra.rb +7 -7
- data/lib/htm/job_adapter.rb +14 -21
- data/lib/htm/jobs/generate_embedding_job.rb +28 -44
- data/lib/htm/jobs/generate_propositions_job.rb +29 -55
- data/lib/htm/jobs/generate_relationships_job.rb +137 -0
- data/lib/htm/jobs/generate_tags_job.rb +45 -67
- data/lib/htm/loaders/markdown_loader.rb +65 -112
- data/lib/htm/long_term_memory/fulltext_search.rb +1 -1
- data/lib/htm/long_term_memory/hybrid_search.rb +300 -128
- data/lib/htm/long_term_memory/node_operations.rb +2 -2
- data/lib/htm/long_term_memory/relevance_scorer.rb +100 -68
- data/lib/htm/long_term_memory/tag_operations.rb +87 -120
- data/lib/htm/long_term_memory/vector_search.rb +1 -1
- data/lib/htm/long_term_memory.rb +2 -1
- data/lib/htm/mcp/cli.rb +59 -58
- data/lib/htm/mcp/server.rb +5 -6
- data/lib/htm/mcp/tools.rb +30 -36
- data/lib/htm/migration.rb +10 -10
- data/lib/htm/models/node.rb +2 -3
- data/lib/htm/models/node_relationship.rb +72 -0
- data/lib/htm/models/node_tag.rb +2 -2
- data/lib/htm/models/robot_node.rb +2 -2
- data/lib/htm/models/tag.rb +41 -28
- data/lib/htm/observability.rb +45 -51
- data/lib/htm/proposition_service.rb +3 -7
- data/lib/htm/query_cache.rb +13 -15
- data/lib/htm/railtie.rb +1 -2
- data/lib/htm/robot_group.rb +9 -9
- data/lib/htm/sequel_config.rb +1 -0
- data/lib/htm/sql_builder.rb +1 -1
- data/lib/htm/tag_service.rb +2 -6
- data/lib/htm/timeframe.rb +4 -5
- data/lib/htm/timeframe_extractor.rb +42 -83
- data/lib/htm/version.rb +1 -1
- data/lib/htm/workflows/remember_workflow.rb +112 -115
- data/lib/htm/working_memory.rb +21 -26
- data/lib/htm.rb +103 -116
- data/lib/tasks/db.rake +0 -2
- data/lib/tasks/doc.rake +14 -13
- data/lib/tasks/files.rake +5 -12
- data/lib/tasks/htm.rake +70 -71
- data/lib/tasks/jobs.rake +41 -47
- data/lib/tasks/tags.rake +3 -8
- metadata +25 -100
|
@@ -189,20 +189,13 @@ end
|
|
|
189
189
|
|
|
190
190
|
```ruby
|
|
191
191
|
# User having back-and-forth coding conversation
|
|
192
|
-
context = htm.
|
|
192
|
+
context = htm.working_memory.assemble_context(strategy: :recent, max_tokens: 8000)
|
|
193
193
|
# Recent messages prioritized for coherent conversation flow
|
|
194
194
|
```
|
|
195
195
|
|
|
196
|
-
#### 2.
|
|
196
|
+
#### 2. Frequent (`:frequent`)
|
|
197
197
|
|
|
198
|
-
Sort by
|
|
199
|
-
|
|
200
|
-
```ruby
|
|
201
|
-
def assemble_context(strategy: :important, max_tokens: nil)
|
|
202
|
-
nodes = @nodes.sort_by { |k, v| -v[:importance] }.map(&:last)
|
|
203
|
-
build_context(nodes, max_tokens || @max_tokens)
|
|
204
|
-
end
|
|
205
|
-
```
|
|
198
|
+
Sort by access count, most accessed first.
|
|
206
199
|
|
|
207
200
|
**Best For:**
|
|
208
201
|
|
|
@@ -215,8 +208,8 @@ end
|
|
|
215
208
|
|
|
216
209
|
```ruby
|
|
217
210
|
# LLM helping with architectural review
|
|
218
|
-
context = htm.
|
|
219
|
-
#
|
|
211
|
+
context = htm.working_memory.assemble_context(strategy: :frequent)
|
|
212
|
+
# Most frequently accessed decisions and facts prioritized
|
|
220
213
|
```
|
|
221
214
|
|
|
222
215
|
#### 3. Balanced (`:balanced`) - **Recommended Default**
|
|
@@ -252,7 +245,7 @@ end
|
|
|
252
245
|
|
|
253
246
|
```ruby
|
|
254
247
|
# Code helper assisting with debugging and design
|
|
255
|
-
context = htm.
|
|
248
|
+
context = htm.working_memory.assemble_context(strategy: :balanced)
|
|
256
249
|
# Recent debugging context + important architectural decisions
|
|
257
250
|
```
|
|
258
251
|
|
|
@@ -287,7 +280,7 @@ Long-term memory provides unlimited, durable storage for all memories with advan
|
|
|
287
280
|
|--------|---------|
|
|
288
281
|
| **Purpose** | Permanent knowledge base |
|
|
289
282
|
| **Capacity** | Effectively unlimited |
|
|
290
|
-
| **Storage** | PostgreSQL 16+ with
|
|
283
|
+
| **Storage** | PostgreSQL 16+ with pgvector and pg_trgm |
|
|
291
284
|
| **Access Pattern** | RAG-based retrieval (semantic + temporal) |
|
|
292
285
|
| **Retention** | Permanent (explicit deletion only) |
|
|
293
286
|
| **Lifetime** | Forever (survives process restarts) |
|
|
@@ -298,16 +291,16 @@ Long-term memory provides unlimited, durable storage for all memories with advan
|
|
|
298
291
|
```sql
|
|
299
292
|
CREATE TABLE nodes (
|
|
300
293
|
id BIGSERIAL PRIMARY KEY,
|
|
301
|
-
|
|
302
|
-
|
|
294
|
+
content TEXT NOT NULL,
|
|
295
|
+
content_hash TEXT UNIQUE,
|
|
303
296
|
type TEXT,
|
|
304
|
-
importance REAL DEFAULT 1.0,
|
|
305
297
|
token_count INTEGER,
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
embedding vector(
|
|
298
|
+
metadata JSONB DEFAULT '{}',
|
|
299
|
+
source_id BIGINT REFERENCES file_sources(id),
|
|
300
|
+
embedding vector(3072),
|
|
301
|
+
deleted_at TIMESTAMP,
|
|
309
302
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
310
|
-
|
|
303
|
+
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
311
304
|
);
|
|
312
305
|
|
|
313
306
|
-- HNSW index for vector similarity
|
|
@@ -316,58 +309,44 @@ CREATE INDEX idx_nodes_embedding ON nodes
|
|
|
316
309
|
WITH (m = 16, ef_construction = 64);
|
|
317
310
|
|
|
318
311
|
-- Full-text search
|
|
319
|
-
CREATE INDEX
|
|
320
|
-
USING gin(to_tsvector('english',
|
|
312
|
+
CREATE INDEX idx_nodes_content_gin ON nodes
|
|
313
|
+
USING gin(to_tsvector('english', content));
|
|
321
314
|
```
|
|
322
315
|
|
|
323
|
-
### Why PostgreSQL
|
|
316
|
+
### Why PostgreSQL?
|
|
324
317
|
|
|
325
318
|
**PostgreSQL provides:**
|
|
326
319
|
|
|
327
320
|
- ACID guarantees for data integrity
|
|
328
321
|
- Rich ecosystem and tooling
|
|
329
322
|
- pgvector for vector similarity search
|
|
330
|
-
- Full-text search with GIN indexes
|
|
323
|
+
- Full-text search with GIN indexes and pg_trgm for fuzzy matching
|
|
324
|
+
- Soft delete support via `deleted_at` column
|
|
325
|
+
- JSONB metadata with GIN index for flexible filtering
|
|
331
326
|
- Mature, production-proven
|
|
332
327
|
|
|
333
|
-
**TimescaleDB adds:**
|
|
334
|
-
|
|
335
|
-
- Hypertable partitioning by time
|
|
336
|
-
- Automatic compression (70-90% reduction)
|
|
337
|
-
- Time-range query optimization
|
|
338
|
-
- Retention policies for data lifecycle
|
|
339
|
-
|
|
340
328
|
!!! info "Related ADR"
|
|
341
|
-
See [ADR-001: Use PostgreSQL
|
|
329
|
+
See [ADR-001: Use PostgreSQL for Storage](../architecture/adrs/001-postgresql-timescaledb.md) for complete rationale.
|
|
342
330
|
|
|
343
331
|
### Long-Term Memory Operations
|
|
344
332
|
|
|
345
333
|
#### Add Node
|
|
346
334
|
|
|
347
335
|
```ruby
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
SQL
|
|
354
|
-
|
|
355
|
-
result[0]['id'].to_i
|
|
356
|
-
end
|
|
336
|
+
# High-level API (recommended)
|
|
337
|
+
node_id = htm.remember("PostgreSQL is great for vector search",
|
|
338
|
+
type: :fact,
|
|
339
|
+
tags: ["database:postgresql"],
|
|
340
|
+
metadata: { source: "docs" })
|
|
357
341
|
```
|
|
358
342
|
|
|
359
343
|
**Time Complexity:** O(log n) with B-tree and HNSW indexes
|
|
360
344
|
|
|
361
|
-
#### Retrieve by
|
|
345
|
+
#### Retrieve by ID
|
|
362
346
|
|
|
363
347
|
```ruby
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
SELECT * FROM nodes WHERE key = $1
|
|
367
|
-
SQL
|
|
368
|
-
|
|
369
|
-
result.first
|
|
370
|
-
end
|
|
348
|
+
# Direct model lookup
|
|
349
|
+
node = HTM::Models::Node.first(id: node_id)
|
|
371
350
|
```
|
|
372
351
|
|
|
373
352
|
**Time Complexity:** O(1) with unique index on key
|
|
@@ -447,7 +426,7 @@ Pure semantic similarity using cosine distance between embeddings.
|
|
|
447
426
|
```ruby
|
|
448
427
|
# Query: "database optimization"
|
|
449
428
|
# Finds: "PostgreSQL index tuning", "query performance", "EXPLAIN ANALYZE"
|
|
450
|
-
memories = htm.recall(
|
|
429
|
+
memories = htm.recall("database optimization", timeframe: "last month", strategy: :vector)
|
|
451
430
|
```
|
|
452
431
|
|
|
453
432
|
##### 2. Full-Text Search (`:fulltext`)
|
|
@@ -466,7 +445,7 @@ Keyword-based matching using PostgreSQL GIN indexes.
|
|
|
466
445
|
```ruby
|
|
467
446
|
# Query: "TimescaleDB compression"
|
|
468
447
|
# Finds exact matches for "TimescaleDB" and "compression"
|
|
469
|
-
memories = htm.recall(
|
|
448
|
+
memories = htm.recall("TimescaleDB compression", timeframe: "last week", strategy: :fulltext)
|
|
470
449
|
```
|
|
471
450
|
|
|
472
451
|
##### 3. Hybrid Search (`:hybrid`) - **Recommended**
|
|
@@ -483,7 +462,7 @@ Combines vector and full-text with RRF scoring.
|
|
|
483
462
|
|
|
484
463
|
```ruby
|
|
485
464
|
# Combines semantic similarity AND keyword matching
|
|
486
|
-
memories = htm.recall(
|
|
465
|
+
memories = htm.recall("PostgreSQL performance", timeframe: "last month", strategy: :hybrid)
|
|
487
466
|
```
|
|
488
467
|
|
|
489
468
|
### Performance Characteristics
|
|
@@ -499,11 +478,11 @@ memories = htm.recall(timeframe: "last month", topic: "PostgreSQL performance",
|
|
|
499
478
|
|
|
500
479
|
**Storage Efficiency:**
|
|
501
480
|
|
|
502
|
-
With
|
|
481
|
+
With PostgreSQL TOAST compression:
|
|
503
482
|
|
|
504
|
-
- Text node: ~1KB
|
|
505
|
-
- Node with embedding: ~7KB
|
|
506
|
-
- 100,000 nodes: ~700MB
|
|
483
|
+
- Text node: ~1KB (minimal overhead)
|
|
484
|
+
- Node with embedding: ~7KB (1536-dim float32 vector)
|
|
485
|
+
- 100,000 nodes: ~700MB typical storage
|
|
507
486
|
|
|
508
487
|
## Memory Flow: Add → Evict → Recall
|
|
509
488
|
|
|
@@ -524,7 +503,7 @@ htm.memory_stats[:working_memory]
|
|
|
524
503
|
# }
|
|
525
504
|
|
|
526
505
|
# Add large memory
|
|
527
|
-
htm.
|
|
506
|
+
htm.remember(large_documentation)
|
|
528
507
|
|
|
529
508
|
# HTM automatically:
|
|
530
509
|
# 1. Generates embedding (Ollama: ~50ms)
|
|
@@ -545,8 +524,8 @@ htm.memory_stats[:working_memory]
|
|
|
545
524
|
# }
|
|
546
525
|
|
|
547
526
|
# Evicted nodes still in long-term memory!
|
|
548
|
-
|
|
549
|
-
|
|
527
|
+
# Retrieve via recall with the original content
|
|
528
|
+
evicted_results = htm.recall("old_debug_log", strategy: :fulltext) # Still works
|
|
550
529
|
```
|
|
551
530
|
|
|
552
531
|
## Context Assembly Strategies in Detail
|
|
@@ -556,8 +535,8 @@ evicted_node = htm.retrieve("old_debug_log") # Still works
|
|
|
556
535
|
| Strategy | Sort Key | Best Use Case | Typical Output |
|
|
557
536
|
|----------|----------|---------------|----------------|
|
|
558
537
|
| **Recent** | Access order (newest first) | Conversations, debugging | Recent 5-10 messages |
|
|
559
|
-
| **
|
|
560
|
-
| **Balanced** | `importance / (1 + hours)` | General assistant | Mix of recent +
|
|
538
|
+
| **Frequent** | Access count (highest first) | Planning, decisions | Top 10 most accessed facts |
|
|
539
|
+
| **Balanced** | `importance / (1 + hours)` | General assistant | Mix of recent + frequent |
|
|
561
540
|
|
|
562
541
|
### Code Examples
|
|
563
542
|
|
|
@@ -565,7 +544,7 @@ evicted_node = htm.retrieve("old_debug_log") # Still works
|
|
|
565
544
|
|
|
566
545
|
```ruby
|
|
567
546
|
# Assemble context from most recent memories
|
|
568
|
-
context = htm.
|
|
547
|
+
context = htm.working_memory.assemble_context(strategy: :recent, max_tokens: 8000)
|
|
569
548
|
|
|
570
549
|
# Typical output (recent conversation):
|
|
571
550
|
# """
|
|
@@ -577,17 +556,17 @@ context = htm.create_context(strategy: :recent, max_tokens: 8000)
|
|
|
577
556
|
# """
|
|
578
557
|
```
|
|
579
558
|
|
|
580
|
-
####
|
|
559
|
+
#### Frequent Strategy
|
|
581
560
|
|
|
582
561
|
```ruby
|
|
583
|
-
# Assemble context from most
|
|
584
|
-
context = htm.
|
|
562
|
+
# Assemble context from most frequently accessed memories
|
|
563
|
+
context = htm.working_memory.assemble_context(strategy: :frequent, max_tokens: 4000)
|
|
585
564
|
|
|
586
565
|
# Typical output (critical facts):
|
|
587
566
|
# """
|
|
588
|
-
# Decision: Use PostgreSQL
|
|
589
|
-
# User preference: Always use debug_me over puts (
|
|
590
|
-
# Architecture: Two-tier memory system (
|
|
567
|
+
# Decision: Use PostgreSQL for storage (accessed 10 times)
|
|
568
|
+
# User preference: Always use debug_me over puts (accessed 8 times)
|
|
569
|
+
# Architecture: Two-tier memory system (accessed 7 times)
|
|
591
570
|
# ...
|
|
592
571
|
# """
|
|
593
572
|
```
|
|
@@ -596,13 +575,13 @@ context = htm.create_context(strategy: :important, max_tokens: 4000)
|
|
|
596
575
|
|
|
597
576
|
```ruby
|
|
598
577
|
# Assemble context with time decay
|
|
599
|
-
context = htm.
|
|
578
|
+
context = htm.working_memory.assemble_context(strategy: :balanced)
|
|
600
579
|
|
|
601
580
|
# Typical output (hybrid):
|
|
602
581
|
# """
|
|
603
|
-
# Recent debugging: ValueError in embedding service (
|
|
604
|
-
#
|
|
605
|
-
#
|
|
582
|
+
# Recent debugging: ValueError in embedding service (10 min ago)
|
|
583
|
+
# Current task: Implementing RAG search (1 hour ago)
|
|
584
|
+
# Critical decision: PostgreSQL chosen (accessed 10 times, 3 days ago)
|
|
606
585
|
# ...
|
|
607
586
|
# """
|
|
608
587
|
```
|
|
@@ -624,55 +603,54 @@ htm = HTM.new(working_memory_size: 128_000) # Default
|
|
|
624
603
|
#### 2. Adjust Importance Scores
|
|
625
604
|
|
|
626
605
|
```ruby
|
|
627
|
-
#
|
|
628
|
-
htm.
|
|
606
|
+
# Store critical information
|
|
607
|
+
htm.remember("User prefers Vim keybindings", metadata: { priority: "high" })
|
|
629
608
|
|
|
630
|
-
#
|
|
631
|
-
htm.
|
|
609
|
+
# Store transient information
|
|
610
|
+
htm.remember("Temporary debug output", metadata: { category: "debug" })
|
|
632
611
|
|
|
633
|
-
#
|
|
634
|
-
htm.
|
|
612
|
+
# Store general context
|
|
613
|
+
htm.remember("Discussed API design patterns")
|
|
635
614
|
```
|
|
636
615
|
|
|
637
616
|
#### 3. Use Appropriate Context Strategy
|
|
638
617
|
|
|
639
618
|
```ruby
|
|
640
619
|
# For chat: recent strategy
|
|
641
|
-
chat_context = htm.
|
|
620
|
+
chat_context = htm.working_memory.assemble_context(strategy: :recent, max_tokens: 8000)
|
|
642
621
|
|
|
643
|
-
# For planning:
|
|
644
|
-
planning_context = htm.
|
|
622
|
+
# For planning: frequent strategy
|
|
623
|
+
planning_context = htm.working_memory.assemble_context(strategy: :frequent, max_tokens: 4000)
|
|
645
624
|
|
|
646
625
|
# For general: balanced strategy (default)
|
|
647
|
-
general_context = htm.
|
|
626
|
+
general_context = htm.working_memory.assemble_context(strategy: :balanced)
|
|
648
627
|
```
|
|
649
628
|
|
|
650
629
|
### Long-Term Memory Optimization
|
|
651
630
|
|
|
652
|
-
#### 1. Leverage
|
|
631
|
+
#### 1. Leverage PostgreSQL Partitioning
|
|
653
632
|
|
|
654
633
|
```sql
|
|
655
|
-
--
|
|
656
|
-
|
|
634
|
+
-- Create a partial index for active (non-deleted) nodes
|
|
635
|
+
CREATE INDEX CONCURRENTLY idx_nodes_active
|
|
636
|
+
ON nodes (created_at DESC)
|
|
637
|
+
WHERE deleted_at IS NULL;
|
|
657
638
|
|
|
658
|
-
--
|
|
659
|
-
|
|
660
|
-
timescaledb.compress,
|
|
661
|
-
timescaledb.compress_segmentby = 'robot_id,type'
|
|
662
|
-
);
|
|
639
|
+
-- Periodically VACUUM to reclaim space from soft-deleted rows
|
|
640
|
+
VACUUM ANALYZE nodes;
|
|
663
641
|
```
|
|
664
642
|
|
|
665
643
|
#### 2. Use Appropriate Search Strategy
|
|
666
644
|
|
|
667
645
|
```ruby
|
|
668
646
|
# For exact matches: full-text
|
|
669
|
-
exact_matches = htm.recall(timeframe: "last week",
|
|
647
|
+
exact_matches = htm.recall("PostgreSQL", timeframe: "last week", strategy: :fulltext)
|
|
670
648
|
|
|
671
649
|
# For semantic similarity: vector
|
|
672
|
-
similar_concepts = htm.recall(
|
|
650
|
+
similar_concepts = htm.recall("database performance", timeframe: "last month", strategy: :vector)
|
|
673
651
|
|
|
674
652
|
# For best results: hybrid (default)
|
|
675
|
-
best_results = htm.recall(
|
|
653
|
+
best_results = htm.recall("PostgreSQL performance", timeframe: "last month", strategy: :hybrid)
|
|
676
654
|
```
|
|
677
655
|
|
|
678
656
|
#### 3. Index Tuning
|
|
@@ -36,24 +36,7 @@ psql --version
|
|
|
36
36
|
brew install pgvector
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
### 2.2
|
|
40
|
-
|
|
41
|
-
```bash
|
|
42
|
-
# Add TimescaleDB tap
|
|
43
|
-
brew tap timescale/tap
|
|
44
|
-
|
|
45
|
-
# Install TimescaleDB
|
|
46
|
-
brew install timescaledb
|
|
47
|
-
|
|
48
|
-
# Configure PostgreSQL for TimescaleDB
|
|
49
|
-
# This updates your postgresql.conf with TimescaleDB settings
|
|
50
|
-
timescaledb-tune --quiet --yes
|
|
51
|
-
|
|
52
|
-
# Restart PostgreSQL to load TimescaleDB
|
|
53
|
-
brew services restart postgresql@17
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### 2.3 pg_trgm (Trigram Matching)
|
|
39
|
+
### 2.2 pg_trgm (Trigram Matching)
|
|
57
40
|
|
|
58
41
|
This extension is included with PostgreSQL, no installation needed.
|
|
59
42
|
|
|
@@ -96,9 +79,6 @@ createdb htm_development
|
|
|
96
79
|
# Enable pgvector
|
|
97
80
|
psql -d htm_development -c "CREATE EXTENSION IF NOT EXISTS vector;"
|
|
98
81
|
|
|
99
|
-
# Enable TimescaleDB
|
|
100
|
-
psql -d htm_development -c "CREATE EXTENSION IF NOT EXISTS timescaledb;"
|
|
101
|
-
|
|
102
82
|
# Enable pg_trgm (trigram matching)
|
|
103
83
|
psql -d htm_development -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;"
|
|
104
84
|
```
|
|
@@ -112,20 +92,15 @@ be rake htm:db:setup
|
|
|
112
92
|
This will:
|
|
113
93
|
1. Verify extensions are available
|
|
114
94
|
2. Create HTM schema (tables, indexes, triggers)
|
|
115
|
-
3.
|
|
116
|
-
4. Run any pending migrations
|
|
95
|
+
3. Run any pending migrations
|
|
117
96
|
|
|
118
97
|
Expected output:
|
|
119
98
|
|
|
120
99
|
```
|
|
121
|
-
✓ TimescaleDB version: X.X.X
|
|
122
100
|
✓ pgvector version: X.X.X
|
|
123
101
|
✓ pg_trgm version: X.X.X
|
|
124
102
|
Creating HTM schema...
|
|
125
103
|
✓ Schema created
|
|
126
|
-
✓ Created hypertable for operations_log
|
|
127
|
-
✓ Created hypertable for nodes
|
|
128
|
-
✓ Enabled compression for nodes older than 30 days
|
|
129
104
|
✓ HTM database schema created successfully
|
|
130
105
|
```
|
|
131
106
|
|
|
@@ -176,17 +151,13 @@ brew install pgvector
|
|
|
176
151
|
psql -d htm_development -c "CREATE EXTENSION IF NOT EXISTS vector;"
|
|
177
152
|
```
|
|
178
153
|
|
|
179
|
-
### Error: "
|
|
154
|
+
### Error: "pg_trgm extension not found"
|
|
180
155
|
|
|
181
|
-
**Problem:**
|
|
156
|
+
**Problem:** pg_trgm not enabled (it ships with PostgreSQL but needs to be enabled).
|
|
182
157
|
|
|
183
158
|
**Solution:**
|
|
184
159
|
```bash
|
|
185
|
-
|
|
186
|
-
brew install timescaledb
|
|
187
|
-
timescaledb-tune --quiet --yes
|
|
188
|
-
brew services restart postgresql@17
|
|
189
|
-
psql -d htm_development -c "CREATE EXTENSION IF NOT EXISTS timescaledb;"
|
|
160
|
+
psql -d htm_development -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;"
|
|
190
161
|
```
|
|
191
162
|
|
|
192
163
|
### Error: "Connection refused" to Ollama
|
|
@@ -212,27 +183,12 @@ direnv allow
|
|
|
212
183
|
echo $HTM_DATABASE__URL # Verify it's set
|
|
213
184
|
```
|
|
214
185
|
|
|
215
|
-
## Switching
|
|
186
|
+
## Switching to a Remote Database
|
|
216
187
|
|
|
217
|
-
To switch
|
|
188
|
+
To switch to a remote PostgreSQL database (e.g. production), update your environment:
|
|
218
189
|
|
|
219
190
|
```bash
|
|
220
|
-
|
|
221
|
-
# export HTM_DATABASE__HOST=localhost
|
|
222
|
-
# export HTM_DATABASE__PORT=5432
|
|
223
|
-
# export HTM_DATABASE__NAME=htm_development
|
|
224
|
-
# export HTM_DATABASE__USER=${USER}
|
|
225
|
-
# export HTM_DATABASE__PASSWORD=
|
|
226
|
-
# export HTM_DATABASE__URL="postgresql://${HTM_DATABASE__USER}@${HTM_DATABASE__HOST}:${HTM_DATABASE__PORT}/${HTM_DATABASE__NAME}?sslmode=prefer"
|
|
227
|
-
|
|
228
|
-
# Uncomment TimescaleDB Cloud config
|
|
229
|
-
export HTM_SERVICE_NAME=$TIGER_SERVICE_NAME
|
|
230
|
-
export HTM_DATABASE__URL=$TIGER_DBURL
|
|
231
|
-
export HTM_DATABASE__NAME=$TIGER_DBNAME
|
|
232
|
-
export HTM_DATABASE__USER=$TIGER_DBUSER
|
|
233
|
-
export HTM_DATABASE__PASSWORD=$TIGER_DBPASS
|
|
234
|
-
export HTM_DATABASE__HOST=$TIGER_DBHOST
|
|
235
|
-
export HTM_DATABASE__PORT=$TIGER_DBPORT
|
|
191
|
+
export HTM_DATABASE__URL="postgresql://user:password@remote-host:5432/htm_production"
|
|
236
192
|
```
|
|
237
193
|
|
|
238
194
|
Then reload:
|
|
@@ -266,14 +222,12 @@ PostgreSQL Version:
|
|
|
266
222
|
Extensions:
|
|
267
223
|
pg_trgm (X.X.X)
|
|
268
224
|
plpgsql (X.X.X)
|
|
269
|
-
timescaledb (X.X.X)
|
|
270
225
|
vector (X.X.X)
|
|
271
226
|
|
|
272
227
|
HTM Tables:
|
|
273
228
|
nodes: X rows
|
|
274
229
|
tags: X rows
|
|
275
230
|
robots: X rows
|
|
276
|
-
operations_log: X rows
|
|
277
231
|
schema_migrations: X rows
|
|
278
232
|
|
|
279
233
|
Database Size: XX MB
|
|
@@ -66,10 +66,10 @@ Create a `.envrc` file in your application's root:
|
|
|
66
66
|
export HTM_DATABASE__URL="postgresql://user:password@host:port/dbname?sslmode=require"
|
|
67
67
|
|
|
68
68
|
# Or use individual parameters
|
|
69
|
-
export HTM_DATABASE__HOST="your-host.
|
|
70
|
-
export HTM_DATABASE__PORT="
|
|
71
|
-
export HTM_DATABASE__NAME="
|
|
72
|
-
export HTM_DATABASE__USER="
|
|
69
|
+
export HTM_DATABASE__HOST="your-db-host.example.com"
|
|
70
|
+
export HTM_DATABASE__PORT="5432"
|
|
71
|
+
export HTM_DATABASE__NAME="htm_production"
|
|
72
|
+
export HTM_DATABASE__USER="postgres"
|
|
73
73
|
export HTM_DATABASE__PASSWORD="your_password"
|
|
74
74
|
|
|
75
75
|
# Embedding configuration
|
|
@@ -277,7 +277,7 @@ jobs:
|
|
|
277
277
|
|
|
278
278
|
services:
|
|
279
279
|
postgres:
|
|
280
|
-
image:
|
|
280
|
+
image: pgvector/pgvector:pg17
|
|
281
281
|
env:
|
|
282
282
|
POSTGRES_PASSWORD: postgres
|
|
283
283
|
options: >-
|
|
@@ -323,7 +323,7 @@ services:
|
|
|
323
323
|
command: bash -c "rake htm:db:setup && rake app:start"
|
|
324
324
|
|
|
325
325
|
db:
|
|
326
|
-
image:
|
|
326
|
+
image: pgvector/pgvector:pg17
|
|
327
327
|
environment:
|
|
328
328
|
- POSTGRES_PASSWORD=postgres
|
|
329
329
|
```
|
data/examples/01_basic_usage.rb
CHANGED
|
@@ -19,6 +19,7 @@ ExamplesHelper.section "HTM Custom LLM Configuration Example"
|
|
|
19
19
|
ExamplesHelper.print_environment
|
|
20
20
|
|
|
21
21
|
# Verify database is available
|
|
22
|
+
ExamplesHelper.reset_if_requested!
|
|
22
23
|
ExamplesHelper.require_database!
|
|
23
24
|
|
|
24
25
|
# Example 1: Use Default Configuration (RubyLLM with Ollama)
|
data/examples/09_mcp_client.rb
CHANGED
|
@@ -2,18 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
source 'https://rubygems.org'
|
|
4
4
|
|
|
5
|
-
# Rails - full-stack setup
|
|
6
|
-
gem 'rails', '~>
|
|
5
|
+
# Rails 8.1 - full-stack setup
|
|
6
|
+
gem 'rails', '~> 8.1'
|
|
7
7
|
gem 'puma', '~> 6.0'
|
|
8
8
|
|
|
9
9
|
# HTM (use local development version)
|
|
10
10
|
gem 'htm', path: '../..'
|
|
11
11
|
|
|
12
|
+
# RubyLLM for chat persistence
|
|
13
|
+
gem 'ruby_llm', '>= 1.0'
|
|
14
|
+
|
|
12
15
|
# PostgreSQL (required for HTM)
|
|
13
16
|
gem 'pg', '~> 1.5'
|
|
14
17
|
|
|
15
|
-
# Ruby
|
|
18
|
+
# Ruby 3.2+ bundled gems (no longer in stdlib)
|
|
16
19
|
gem 'ostruct'
|
|
20
|
+
gem 'logger'
|
|
21
|
+
gem 'benchmark'
|
|
17
22
|
|
|
18
23
|
# Frontend - using CDN for Tailwind and Hotwire (no build step)
|
|
19
24
|
gem 'propshaft' # Asset pipeline for CSS/images
|