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
|
@@ -52,10 +52,10 @@ Context assembly transforms working memory into LLM-ready context:
|
|
|
52
52
|
<text x="350" y="120" class="text-label">:recent</text>
|
|
53
53
|
<text x="550" y="120" text-anchor="end" class="text-small">Sort by access time</text>
|
|
54
54
|
|
|
55
|
-
<!-- Strategy 2:
|
|
55
|
+
<!-- Strategy 2: Frequent -->
|
|
56
56
|
<rect x="340" y="145" width="220" height="35" fill="rgba(76, 175, 80, 0.3)" rx="3"/>
|
|
57
|
-
<text x="350" y="165" class="text-label">:
|
|
58
|
-
<text x="550" y="165" text-anchor="end" class="text-small">Sort by
|
|
57
|
+
<text x="350" y="165" class="text-label">:frequent</text>
|
|
58
|
+
<text x="550" y="165" text-anchor="end" class="text-small">Sort by access count</text>
|
|
59
59
|
|
|
60
60
|
<!-- Strategy 3: Balanced -->
|
|
61
61
|
<rect x="340" y="190" width="220" height="35" fill="rgba(76, 175, 80, 0.3)" rx="3"/>
|
|
@@ -70,7 +70,7 @@ Context assembly transforms working memory into LLM-ready context:
|
|
|
70
70
|
<text x="750" y="105" text-anchor="middle" class="text-small">(Ordered)</text>
|
|
71
71
|
|
|
72
72
|
<text x="660" y="135" class="text-label">Node 3</text>
|
|
73
|
-
<text x="840" y="135" text-anchor="end" class="text-small">(
|
|
73
|
+
<text x="840" y="135" text-anchor="end" class="text-small">(frequent)</text>
|
|
74
74
|
<text x="660" y="155" class="text-label">Node 1</text>
|
|
75
75
|
<text x="840" y="155" text-anchor="end" class="text-small">(recent)</text>
|
|
76
76
|
<text x="660" y="175" class="text-label">Node 5</text>
|
data/docs/guides/file-loading.md
CHANGED
|
@@ -125,7 +125,7 @@ Content starts here...
|
|
|
125
125
|
Access frontmatter via the FileSource model:
|
|
126
126
|
|
|
127
127
|
```ruby
|
|
128
|
-
source = HTM::Models::FileSource.
|
|
128
|
+
source = HTM::Models::FileSource.first(file_path: "docs/guide.md")
|
|
129
129
|
source.title # => "PostgreSQL Guide"
|
|
130
130
|
source.author # => "HTM Team"
|
|
131
131
|
source.frontmatter_tags # => ["database", "postgresql"]
|
|
@@ -146,13 +146,13 @@ HTM uses the [Baran gem](https://github.com/baran) with `MarkdownSplitter` for i
|
|
|
146
146
|
```ruby
|
|
147
147
|
# Global configuration
|
|
148
148
|
HTM.configure do |config|
|
|
149
|
-
config.chunk_size = 1024 # Characters per chunk (default: 1024)
|
|
150
|
-
config.chunk_overlap = 64 # Overlap between chunks (default: 64)
|
|
149
|
+
config.chunking.chunk_size = 1024 # Characters per chunk (default: 1024)
|
|
150
|
+
config.chunking.chunk_overlap = 64 # Overlap between chunks (default: 64)
|
|
151
151
|
end
|
|
152
152
|
|
|
153
153
|
# Or via environment variables
|
|
154
|
-
#
|
|
155
|
-
#
|
|
154
|
+
# HTM_CHUNKING__CHUNK_SIZE=512
|
|
155
|
+
# HTM_CHUNKING__CHUNK_OVERLAP=50
|
|
156
156
|
```
|
|
157
157
|
|
|
158
158
|
### Per-Loader Configuration
|
|
@@ -198,7 +198,7 @@ htm.load_file("docs/guide.md", force: true)
|
|
|
198
198
|
The `HTM::Models::FileSource` tracks loaded files:
|
|
199
199
|
|
|
200
200
|
```ruby
|
|
201
|
-
source = HTM::Models::FileSource.
|
|
201
|
+
source = HTM::Models::FileSource.first(file_path: "docs/guide.md")
|
|
202
202
|
|
|
203
203
|
source.file_path # Full path to file
|
|
204
204
|
source.mtime # Last modification time
|
|
@@ -269,17 +269,17 @@ priority: high
|
|
|
269
269
|
|
|
270
270
|
```ruby
|
|
271
271
|
# Smaller chunks for dense technical content
|
|
272
|
-
HTM.configure { |c| c.chunk_size = 512 }
|
|
272
|
+
HTM.configure { |c| c.chunking.chunk_size = 512 }
|
|
273
273
|
|
|
274
274
|
# Larger chunks for narrative content
|
|
275
|
-
HTM.configure { |c| c.chunk_size = 2048 }
|
|
275
|
+
HTM.configure { |c| c.chunking.chunk_size = 2048 }
|
|
276
276
|
```
|
|
277
277
|
|
|
278
278
|
### Regular Sync for Updated Content
|
|
279
279
|
|
|
280
280
|
```ruby
|
|
281
|
-
# Sync all loaded files periodically
|
|
282
|
-
htm
|
|
281
|
+
# Sync all loaded files periodically (via rake task)
|
|
282
|
+
# rake htm:files:sync # Re-checks all FileSource records
|
|
283
283
|
```
|
|
284
284
|
|
|
285
285
|
## Example: Building a Knowledge Base
|
|
@@ -292,8 +292,8 @@ htm = HTM.new(robot_name: "Knowledge Base")
|
|
|
292
292
|
|
|
293
293
|
# Configure chunking for technical docs
|
|
294
294
|
HTM.configure do |config|
|
|
295
|
-
config.chunk_size = 768
|
|
296
|
-
config.chunk_overlap = 100
|
|
295
|
+
config.chunking.chunk_size = 768
|
|
296
|
+
config.chunking.chunk_overlap = 100
|
|
297
297
|
end
|
|
298
298
|
|
|
299
299
|
# Load documentation
|
|
@@ -7,7 +7,7 @@ Welcome to HTM! This guide will help you build your first intelligent memory sys
|
|
|
7
7
|
Before starting, ensure you have:
|
|
8
8
|
|
|
9
9
|
1. **Ruby 3.0+** installed
|
|
10
|
-
2. **PostgreSQL with
|
|
10
|
+
2. **PostgreSQL 16+** with pgvector and pg_trgm extensions
|
|
11
11
|
3. **LLM Provider** configured - Ollama (default for local development), OpenAI, Anthropic, Gemini, or others via RubyLLM
|
|
12
12
|
4. Basic understanding of Ruby and LLMs
|
|
13
13
|
|
|
@@ -72,7 +72,7 @@ gem install htm
|
|
|
72
72
|
|
|
73
73
|
## Database Setup
|
|
74
74
|
|
|
75
|
-
HTM requires a
|
|
75
|
+
HTM requires a PostgreSQL database with pgvector and pg_trgm. Set your database connection:
|
|
76
76
|
|
|
77
77
|
```bash
|
|
78
78
|
# Add to your .bashrc or .zshrc
|
|
@@ -9,7 +9,7 @@ Long-term memory provides:
|
|
|
9
9
|
- **Permanent storage** for all memories
|
|
10
10
|
- **Vector embeddings** via pgvector
|
|
11
11
|
- **Full-text search** via PostgreSQL's ts_vector
|
|
12
|
-
- **
|
|
12
|
+
- **Temporal filtering** via created_at index and Chronic gem for natural language timeframes
|
|
13
13
|
- **Relationship graphs** for knowledge connections
|
|
14
14
|
- **Audit logging** for all operations
|
|
15
15
|
|
|
@@ -383,33 +383,13 @@ conn.close
|
|
|
383
383
|
puts "Reindexing completed"
|
|
384
384
|
```
|
|
385
385
|
|
|
386
|
-
###
|
|
386
|
+
### Cleanup Old Soft-Deleted Nodes
|
|
387
387
|
|
|
388
|
-
|
|
388
|
+
Periodically purge soft-deleted nodes to reclaim storage:
|
|
389
389
|
|
|
390
390
|
```ruby
|
|
391
|
-
#
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
conn.exec(
|
|
395
|
-
<<~SQL
|
|
396
|
-
ALTER TABLE operations_log SET (
|
|
397
|
-
timescaledb.compress,
|
|
398
|
-
timescaledb.compress_segmentby = 'robot_id'
|
|
399
|
-
)
|
|
400
|
-
SQL
|
|
401
|
-
)
|
|
402
|
-
|
|
403
|
-
# Add compression policy (compress data older than 7 days)
|
|
404
|
-
conn.exec(
|
|
405
|
-
<<~SQL
|
|
406
|
-
SELECT add_compression_policy('operations_log', INTERVAL '7 days')
|
|
407
|
-
SQL
|
|
408
|
-
)
|
|
409
|
-
|
|
410
|
-
conn.close
|
|
411
|
-
|
|
412
|
-
puts "Compression policy enabled"
|
|
391
|
+
# Purge nodes soft-deleted more than 90 days ago
|
|
392
|
+
htm.purge_deleted(older_than: Time.now - (90 * 24 * 60 * 60), confirm: :confirmed)
|
|
413
393
|
```
|
|
414
394
|
|
|
415
395
|
### Cleanup Old Logs
|
|
@@ -882,9 +862,9 @@ puts "Total nodes: #{HTM::Models::Node.count}"
|
|
|
882
862
|
puts "Total tags: #{HTM::Models::Tag.count}"
|
|
883
863
|
puts "Active robots: #{HTM::Models::Robot.count}"
|
|
884
864
|
|
|
885
|
-
# Query by tag
|
|
865
|
+
# Query by tag
|
|
886
866
|
puts "\n=== Query by Tag ==="
|
|
887
|
-
test_tag = HTM::Models::Tag.
|
|
867
|
+
test_tag = HTM::Models::Tag.first(name: "test")
|
|
888
868
|
if test_tag
|
|
889
869
|
tagged_nodes = test_tag.nodes
|
|
890
870
|
puts "Found #{tagged_nodes.count} nodes with tag 'test'"
|
data/docs/guides/propositions.md
CHANGED
|
@@ -40,13 +40,13 @@ A proposition is an atomic factual statement that:
|
|
|
40
40
|
```ruby
|
|
41
41
|
# Via configuration block
|
|
42
42
|
HTM.configure do |config|
|
|
43
|
-
config.
|
|
44
|
-
config.
|
|
45
|
-
config.
|
|
43
|
+
config.proposition.enabled = true
|
|
44
|
+
config.proposition.provider = :ollama # or :openai, :anthropic, etc.
|
|
45
|
+
config.proposition.model = 'gemma3:latest'
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
# Or via environment variable
|
|
49
|
-
#
|
|
49
|
+
# HTM_PROPOSITION__ENABLED=true
|
|
50
50
|
```
|
|
51
51
|
|
|
52
52
|
### Provider Options
|
|
@@ -62,11 +62,11 @@ Proposition extraction uses LLM chat completion. Configure your preferred provid
|
|
|
62
62
|
|
|
63
63
|
```ruby
|
|
64
64
|
HTM.configure do |config|
|
|
65
|
-
config.
|
|
65
|
+
config.proposition.enabled = true
|
|
66
66
|
|
|
67
67
|
# Use OpenAI for higher quality extraction
|
|
68
|
-
config.
|
|
69
|
-
config.
|
|
68
|
+
config.proposition.provider = :openai
|
|
69
|
+
config.proposition.model = 'gpt-4o-mini'
|
|
70
70
|
end
|
|
71
71
|
```
|
|
72
72
|
|
|
@@ -150,13 +150,14 @@ propositions.each { |p| htm.remember(p) }
|
|
|
150
150
|
|
|
151
151
|
```ruby
|
|
152
152
|
# Find all proposition nodes
|
|
153
|
-
propositions = HTM::Models::Node.where(
|
|
153
|
+
propositions = HTM::Models::Node.where(
|
|
154
|
+
Sequel.lit("metadata->>'is_proposition' = ?", 'true')
|
|
155
|
+
)
|
|
154
156
|
|
|
155
157
|
# Find propositions from a specific source
|
|
156
158
|
source_node_id = 123
|
|
157
159
|
related = HTM::Models::Node.where(
|
|
158
|
-
"metadata->>'source_node_id' = ?",
|
|
159
|
-
source_node_id.to_s
|
|
160
|
+
Sequel.lit("metadata->>'source_node_id' = ?", source_node_id.to_s)
|
|
160
161
|
)
|
|
161
162
|
|
|
162
163
|
# Include propositions in recall (default behavior)
|
|
@@ -193,8 +194,8 @@ With async job backend, extraction happens in background:
|
|
|
193
194
|
|
|
194
195
|
```ruby
|
|
195
196
|
HTM.configure do |config|
|
|
196
|
-
config.
|
|
197
|
-
config.job.backend = :
|
|
197
|
+
config.proposition.enabled = true
|
|
198
|
+
config.job.backend = :fiber # or :sidekiq
|
|
198
199
|
end
|
|
199
200
|
|
|
200
201
|
# Returns immediately, propositions created async
|
|
@@ -229,12 +230,12 @@ Use a capable model for better extraction:
|
|
|
229
230
|
|
|
230
231
|
```ruby
|
|
231
232
|
# Higher quality (slower, costs more)
|
|
232
|
-
config.
|
|
233
|
-
config.
|
|
233
|
+
config.proposition.provider = :openai
|
|
234
|
+
config.proposition.model = 'gpt-4o'
|
|
234
235
|
|
|
235
236
|
# Balanced (faster, local)
|
|
236
|
-
config.
|
|
237
|
-
config.
|
|
237
|
+
config.proposition.provider = :ollama
|
|
238
|
+
config.proposition.model = 'gemma3:latest'
|
|
238
239
|
```
|
|
239
240
|
|
|
240
241
|
### Selective Extraction
|
|
@@ -243,10 +244,10 @@ Enable/disable per operation if needed:
|
|
|
243
244
|
|
|
244
245
|
```ruby
|
|
245
246
|
# Temporarily disable for specific content
|
|
246
|
-
original_setting = HTM.
|
|
247
|
-
HTM.
|
|
247
|
+
original_setting = HTM.config.proposition.enabled
|
|
248
|
+
HTM.config.proposition.enabled = false
|
|
248
249
|
htm.remember("Simple fact that doesn't need decomposition.")
|
|
249
|
-
HTM.
|
|
250
|
+
HTM.config.proposition.enabled = original_setting
|
|
250
251
|
```
|
|
251
252
|
|
|
252
253
|
## Rake Tasks
|
|
@@ -625,11 +625,11 @@ For known node IDs, access the node directly via the model:
|
|
|
625
625
|
|
|
626
626
|
```ruby
|
|
627
627
|
# Look up by node ID
|
|
628
|
-
node = HTM::Models::Node.
|
|
628
|
+
node = HTM::Models::Node.first(id: node_id)
|
|
629
629
|
|
|
630
630
|
if node
|
|
631
631
|
puts node.content
|
|
632
|
-
puts "Tags: #{node.
|
|
632
|
+
puts "Tags: #{node.tag_names.join(', ')}"
|
|
633
633
|
puts "Created: #{node.created_at}"
|
|
634
634
|
else
|
|
635
635
|
puts "Memory not found"
|
|
@@ -792,10 +792,10 @@ Times vary based on database size and query complexity.
|
|
|
792
792
|
|
|
793
793
|
```ruby
|
|
794
794
|
# Slow: Wide timeframe + high limit
|
|
795
|
-
htm.recall(timeframe: "last 5 years",
|
|
795
|
+
htm.recall("...", timeframe: "last 5 years", limit: 1000)
|
|
796
796
|
|
|
797
797
|
# Fast: Narrow timeframe + reasonable limit
|
|
798
|
-
htm.recall(timeframe: "last week",
|
|
798
|
+
htm.recall("...", timeframe: "last week", limit: 20)
|
|
799
799
|
```
|
|
800
800
|
|
|
801
801
|
### Caching Results
|
|
@@ -860,7 +860,7 @@ good_results = results.select do |m|
|
|
|
860
860
|
end
|
|
861
861
|
|
|
862
862
|
# Or boost limit and take top results
|
|
863
|
-
htm.recall(
|
|
863
|
+
htm.recall("...", timeframe: "...", limit: 100, raw: true)
|
|
864
864
|
.sort_by { |m| -m['similarity'].to_f }
|
|
865
865
|
.first(10)
|
|
866
866
|
```
|
data/docs/guides/tags.md
CHANGED
|
@@ -121,11 +121,19 @@ htm.long_term_memory.add_tag(node_id: node.id, tag: "new:tag")
|
|
|
121
121
|
tags = htm.long_term_memory.node_topics(node.id)
|
|
122
122
|
# => ["database:postgresql", "search:vector"]
|
|
123
123
|
|
|
124
|
-
# Find nodes by tag
|
|
125
|
-
nodes = HTM::Models::Node
|
|
124
|
+
# Find nodes by tag (via Sequel)
|
|
125
|
+
nodes = HTM::Models::Node
|
|
126
|
+
.join(:nodes_tags, node_id: :id)
|
|
127
|
+
.join(:tags, id: :tag_id)
|
|
128
|
+
.where(Sequel[:tags][:name] => "database:postgresql")
|
|
129
|
+
.all
|
|
126
130
|
|
|
127
131
|
# Find by tag prefix
|
|
128
|
-
nodes = HTM::Models::Node
|
|
132
|
+
nodes = HTM::Models::Node
|
|
133
|
+
.join(:nodes_tags, node_id: :id)
|
|
134
|
+
.join(:tags, id: :tag_id)
|
|
135
|
+
.where(Sequel.like(Sequel[:tags][:name], "database:%"))
|
|
136
|
+
.all
|
|
129
137
|
```
|
|
130
138
|
|
|
131
139
|
### Tag Relationships
|
|
@@ -218,15 +226,15 @@ rake htm:tags:rebuild
|
|
|
218
226
|
|
|
219
227
|
```ruby
|
|
220
228
|
# Filter by specific tag
|
|
221
|
-
results = htm.recall("query",
|
|
229
|
+
results = htm.recall("query", query_tags: ["database:postgresql"])
|
|
222
230
|
|
|
223
231
|
# Filter by multiple tags (AND)
|
|
224
|
-
results = htm.recall("query",
|
|
232
|
+
results = htm.recall("query", query_tags: ["database:postgresql", "search:vector"])
|
|
225
233
|
|
|
226
234
|
# Combine with other filters
|
|
227
235
|
results = htm.recall(
|
|
228
236
|
"performance optimization",
|
|
229
|
-
|
|
237
|
+
query_tags: ["database:postgresql"],
|
|
230
238
|
timeframe: "last week",
|
|
231
239
|
strategy: :hybrid,
|
|
232
240
|
limit: 10
|
|
@@ -236,14 +244,11 @@ results = htm.recall(
|
|
|
236
244
|
### Direct Queries
|
|
237
245
|
|
|
238
246
|
```ruby
|
|
239
|
-
# Find all nodes with a tag
|
|
240
|
-
|
|
247
|
+
# Find all nodes with a specific tag (via LongTermMemory)
|
|
248
|
+
results = htm.long_term_memory.search_by_tags(tags: ["database:postgresql"])
|
|
241
249
|
|
|
242
|
-
# Find nodes with
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
# Find nodes with all specified tags
|
|
246
|
-
HTM::Models::Node.with_all_tags(["database:postgresql", "search:vector"])
|
|
250
|
+
# Find nodes with multiple tags
|
|
251
|
+
results = htm.long_term_memory.search_by_tags(tags: ["database:postgresql", "search:vector"])
|
|
247
252
|
```
|
|
248
253
|
|
|
249
254
|
## Database Schema
|
|
@@ -75,7 +75,7 @@ end
|
|
|
75
75
|
class MemoriesController < ApplicationController
|
|
76
76
|
def create
|
|
77
77
|
htm = HTM.new(robot_name: "user_#{current_user.id}")
|
|
78
|
-
node_id = htm.remember(params[:content], source: 'user')
|
|
78
|
+
node_id = htm.remember(params[:content], metadata: { source: 'user' })
|
|
79
79
|
|
|
80
80
|
render json: { status: 'ok', node_id: node_id }
|
|
81
81
|
end
|
data/docs/robots/hive-mind.md
CHANGED
|
@@ -188,7 +188,7 @@ def remember(content, tags: [])
|
|
|
188
188
|
content_hash = Digest::SHA256.hexdigest(content)
|
|
189
189
|
|
|
190
190
|
# 2. Check if node with same hash exists
|
|
191
|
-
existing_node = HTM::Models::Node.
|
|
191
|
+
existing_node = HTM::Models::Node.first(content_hash: content_hash)
|
|
192
192
|
|
|
193
193
|
if existing_node
|
|
194
194
|
# 3a. Link robot to existing node (or update remember_count)
|
data/docs/robots/multi-robot.md
CHANGED
|
@@ -187,7 +187,7 @@ timeline = memory_timeline("architecture decisions", limit: 50)
|
|
|
187
187
|
puts "Architecture discussion timeline:"
|
|
188
188
|
timeline.each do |node|
|
|
189
189
|
robot_ids = node.robot_nodes.map(&:robot_id)
|
|
190
|
-
robots = HTM::Models::Robot.where(id: robot_ids).
|
|
190
|
+
robots = HTM::Models::Robot.where(id: robot_ids).select_map(:name)
|
|
191
191
|
|
|
192
192
|
puts "#{node.created_at} - #{robots.join(', ')}"
|
|
193
193
|
puts " #{node.content[0..100]}..."
|
|
@@ -738,7 +738,7 @@ class DevTeam
|
|
|
738
738
|
|
|
739
739
|
nodes.each do |node|
|
|
740
740
|
robot_ids = node.robot_nodes.map(&:robot_id)
|
|
741
|
-
robots = HTM::Models::Robot.where(id: robot_ids).
|
|
741
|
+
robots = HTM::Models::Robot.where(id: robot_ids).select_map(:name)
|
|
742
742
|
puts "- #{robots.join(', ')}: #{node.content[0..50]}..."
|
|
743
743
|
end
|
|
744
744
|
|
data/docs/robots/robot-groups.md
CHANGED
|
@@ -404,7 +404,7 @@ channel.on_change do |event, node_id, origin_robot_id|
|
|
|
404
404
|
|
|
405
405
|
case event
|
|
406
406
|
when :added
|
|
407
|
-
node = HTM::Models::Node.
|
|
407
|
+
node = HTM::Models::Node.first(id: node_id)
|
|
408
408
|
if node
|
|
409
409
|
htm.working_memory.add_from_sync(
|
|
410
410
|
id: node.id,
|