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.
- checksums.yaml +7 -0
- data/.architecture/decisions/adrs/001-use-postgresql-timescaledb-storage.md +227 -0
- data/.architecture/decisions/adrs/002-two-tier-memory-architecture.md +322 -0
- data/.architecture/decisions/adrs/003-ollama-default-embedding-provider.md +339 -0
- data/.architecture/decisions/adrs/004-multi-robot-shared-memory-hive-mind.md +374 -0
- data/.architecture/decisions/adrs/005-rag-based-retrieval-with-hybrid-search.md +443 -0
- data/.architecture/decisions/adrs/006-context-assembly-strategies.md +444 -0
- data/.architecture/decisions/adrs/007-working-memory-eviction-strategy.md +461 -0
- data/.architecture/decisions/adrs/008-robot-identification-system.md +550 -0
- data/.architecture/decisions/adrs/009-never-forget-explicit-deletion-only.md +570 -0
- data/.architecture/decisions/adrs/010-redis-working-memory-rejected.md +323 -0
- data/.architecture/decisions/adrs/011-database-side-embedding-generation-with-pgai.md +585 -0
- data/.architecture/decisions/adrs/012-llm-driven-ontology-topic-extraction.md +583 -0
- data/.architecture/decisions/adrs/013-activerecord-orm-and-many-to-many-tagging.md +299 -0
- data/.architecture/decisions/adrs/014-client-side-embedding-generation-workflow.md +569 -0
- data/.architecture/decisions/adrs/015-hierarchical-tag-ontology-and-llm-extraction.md +701 -0
- data/.architecture/decisions/adrs/016-async-embedding-and-tag-generation.md +694 -0
- data/.architecture/members.yml +144 -0
- data/.architecture/reviews/2025-10-29-llm-configuration-and-async-processing-review.md +1137 -0
- data/.architecture/reviews/initial-system-analysis.md +330 -0
- data/.envrc +32 -0
- data/.irbrc +145 -0
- data/CHANGELOG.md +150 -0
- data/COMMITS.md +196 -0
- data/LICENSE +21 -0
- data/README.md +1347 -0
- data/Rakefile +51 -0
- data/SETUP.md +268 -0
- data/config/database.yml +67 -0
- data/db/migrate/20250101000001_enable_extensions.rb +14 -0
- data/db/migrate/20250101000002_create_robots.rb +14 -0
- data/db/migrate/20250101000003_create_nodes.rb +42 -0
- data/db/migrate/20250101000005_create_tags.rb +38 -0
- data/db/migrate/20250101000007_add_node_vector_indexes.rb +30 -0
- data/db/schema.sql +473 -0
- data/db/seed_data/README.md +100 -0
- data/db/seed_data/presidents.md +136 -0
- data/db/seed_data/states.md +151 -0
- data/db/seeds.rb +208 -0
- data/dbdoc/README.md +173 -0
- data/dbdoc/public.node_stats.md +48 -0
- data/dbdoc/public.node_stats.svg +41 -0
- data/dbdoc/public.node_tags.md +40 -0
- data/dbdoc/public.node_tags.svg +112 -0
- data/dbdoc/public.nodes.md +54 -0
- data/dbdoc/public.nodes.svg +118 -0
- data/dbdoc/public.nodes_tags.md +39 -0
- data/dbdoc/public.nodes_tags.svg +112 -0
- data/dbdoc/public.ontology_structure.md +48 -0
- data/dbdoc/public.ontology_structure.svg +38 -0
- data/dbdoc/public.operations_log.md +42 -0
- data/dbdoc/public.operations_log.svg +130 -0
- data/dbdoc/public.relationships.md +39 -0
- data/dbdoc/public.relationships.svg +41 -0
- data/dbdoc/public.robot_activity.md +46 -0
- data/dbdoc/public.robot_activity.svg +35 -0
- data/dbdoc/public.robots.md +35 -0
- data/dbdoc/public.robots.svg +90 -0
- data/dbdoc/public.schema_migrations.md +29 -0
- data/dbdoc/public.schema_migrations.svg +26 -0
- data/dbdoc/public.tags.md +35 -0
- data/dbdoc/public.tags.svg +60 -0
- data/dbdoc/public.topic_relationships.md +45 -0
- data/dbdoc/public.topic_relationships.svg +32 -0
- data/dbdoc/schema.json +1437 -0
- data/dbdoc/schema.svg +154 -0
- data/docs/api/database.md +806 -0
- data/docs/api/embedding-service.md +532 -0
- data/docs/api/htm.md +797 -0
- data/docs/api/index.md +259 -0
- data/docs/api/long-term-memory.md +1096 -0
- data/docs/api/working-memory.md +665 -0
- data/docs/architecture/adrs/001-postgresql-timescaledb.md +314 -0
- data/docs/architecture/adrs/002-two-tier-memory.md +411 -0
- data/docs/architecture/adrs/003-ollama-embeddings.md +421 -0
- data/docs/architecture/adrs/004-hive-mind.md +437 -0
- data/docs/architecture/adrs/005-rag-retrieval.md +531 -0
- data/docs/architecture/adrs/006-context-assembly.md +496 -0
- data/docs/architecture/adrs/007-eviction-strategy.md +645 -0
- data/docs/architecture/adrs/008-robot-identification.md +625 -0
- data/docs/architecture/adrs/009-never-forget.md +648 -0
- data/docs/architecture/adrs/010-redis-working-memory-rejected.md +323 -0
- data/docs/architecture/adrs/011-pgai-integration.md +494 -0
- data/docs/architecture/adrs/index.md +215 -0
- data/docs/architecture/hive-mind.md +736 -0
- data/docs/architecture/index.md +351 -0
- data/docs/architecture/overview.md +538 -0
- data/docs/architecture/two-tier-memory.md +873 -0
- data/docs/assets/css/custom.css +83 -0
- data/docs/assets/images/htm-core-components.svg +63 -0
- data/docs/assets/images/htm-database-schema.svg +93 -0
- data/docs/assets/images/htm-hive-mind-architecture.svg +125 -0
- data/docs/assets/images/htm-importance-scoring-framework.svg +83 -0
- data/docs/assets/images/htm-layered-architecture.svg +71 -0
- data/docs/assets/images/htm-long-term-memory-architecture.svg +115 -0
- data/docs/assets/images/htm-working-memory-architecture.svg +120 -0
- data/docs/assets/images/htm.jpg +0 -0
- data/docs/assets/images/htm_demo.gif +0 -0
- data/docs/assets/js/mathjax.js +18 -0
- data/docs/assets/videos/htm_video.mp4 +0 -0
- data/docs/database_rake_tasks.md +322 -0
- data/docs/development/contributing.md +787 -0
- data/docs/development/index.md +336 -0
- data/docs/development/schema.md +596 -0
- data/docs/development/setup.md +719 -0
- data/docs/development/testing.md +819 -0
- data/docs/guides/adding-memories.md +824 -0
- data/docs/guides/context-assembly.md +1009 -0
- data/docs/guides/getting-started.md +577 -0
- data/docs/guides/index.md +118 -0
- data/docs/guides/long-term-memory.md +941 -0
- data/docs/guides/multi-robot.md +866 -0
- data/docs/guides/recalling-memories.md +927 -0
- data/docs/guides/search-strategies.md +953 -0
- data/docs/guides/working-memory.md +717 -0
- data/docs/index.md +214 -0
- data/docs/installation.md +477 -0
- data/docs/multi_framework_support.md +519 -0
- data/docs/quick-start.md +655 -0
- data/docs/setup_local_database.md +302 -0
- data/docs/using_rake_tasks_in_your_app.md +383 -0
- data/examples/basic_usage.rb +93 -0
- data/examples/cli_app/README.md +317 -0
- data/examples/cli_app/htm_cli.rb +270 -0
- data/examples/custom_llm_configuration.rb +183 -0
- data/examples/example_app/Rakefile +71 -0
- data/examples/example_app/app.rb +206 -0
- data/examples/sinatra_app/Gemfile +21 -0
- data/examples/sinatra_app/app.rb +335 -0
- data/lib/htm/active_record_config.rb +113 -0
- data/lib/htm/configuration.rb +342 -0
- data/lib/htm/database.rb +594 -0
- data/lib/htm/embedding_service.rb +115 -0
- data/lib/htm/errors.rb +34 -0
- data/lib/htm/job_adapter.rb +154 -0
- data/lib/htm/jobs/generate_embedding_job.rb +65 -0
- data/lib/htm/jobs/generate_tags_job.rb +82 -0
- data/lib/htm/long_term_memory.rb +965 -0
- data/lib/htm/models/node.rb +109 -0
- data/lib/htm/models/node_tag.rb +33 -0
- data/lib/htm/models/robot.rb +52 -0
- data/lib/htm/models/tag.rb +76 -0
- data/lib/htm/railtie.rb +76 -0
- data/lib/htm/sinatra.rb +157 -0
- data/lib/htm/tag_service.rb +135 -0
- data/lib/htm/tasks.rb +38 -0
- data/lib/htm/version.rb +5 -0
- data/lib/htm/working_memory.rb +182 -0
- data/lib/htm.rb +400 -0
- data/lib/tasks/db.rake +19 -0
- data/lib/tasks/htm.rake +147 -0
- data/lib/tasks/jobs.rake +312 -0
- data/mkdocs.yml +190 -0
- data/scripts/install_local_database.sh +309 -0
- metadata +341 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Example: Custom LLM Configuration for HTM
|
|
5
|
+
#
|
|
6
|
+
# This example demonstrates how to configure HTM with custom LLM methods
|
|
7
|
+
# for embedding generation and tag extraction, as well as using defaults.
|
|
8
|
+
|
|
9
|
+
require_relative '../lib/htm'
|
|
10
|
+
|
|
11
|
+
puts "HTM Custom LLM Configuration Example"
|
|
12
|
+
puts "=" * 50
|
|
13
|
+
|
|
14
|
+
# Example 1: Use Default Configuration (RubyLLM with Ollama)
|
|
15
|
+
puts "\n1. Using Default Configuration (RubyLLM + Ollama)"
|
|
16
|
+
puts "-" * 50
|
|
17
|
+
|
|
18
|
+
HTM.configure # Uses defaults
|
|
19
|
+
|
|
20
|
+
htm = HTM.new(robot_name: "DefaultBot")
|
|
21
|
+
puts "✓ HTM initialized with default LLM configuration"
|
|
22
|
+
puts " Embedding provider: #{HTM.configuration.embedding_provider}"
|
|
23
|
+
puts " Embedding model: #{HTM.configuration.embedding_model}"
|
|
24
|
+
puts " Tag provider: #{HTM.configuration.tag_provider}"
|
|
25
|
+
puts " Tag model: #{HTM.configuration.tag_model}"
|
|
26
|
+
|
|
27
|
+
# Example 2: Custom Configuration with Lambdas
|
|
28
|
+
puts "\n2. Custom Configuration with Lambdas"
|
|
29
|
+
puts "-" * 50
|
|
30
|
+
|
|
31
|
+
HTM.configure do |config|
|
|
32
|
+
# Custom embedding generator
|
|
33
|
+
config.embedding_generator = lambda do |text|
|
|
34
|
+
puts " → Custom embedding generator called for: #{text[0..50]}..."
|
|
35
|
+
# Simulate custom embedding service
|
|
36
|
+
# In real application, this would call your LLM infrastructure
|
|
37
|
+
Array.new(768) { rand } # Returns 768-dimensional random vector
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Custom tag extractor
|
|
41
|
+
config.tag_extractor = lambda do |text, existing_ontology|
|
|
42
|
+
puts " → Custom tag extractor called for: #{text[0..50]}..."
|
|
43
|
+
puts " → Existing ontology size: #{existing_ontology.size}"
|
|
44
|
+
# Simulate custom tag extraction
|
|
45
|
+
# In real application, this would call your LLM infrastructure
|
|
46
|
+
['custom:tag:example', 'test:automated']
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
htm = HTM.new(robot_name: "CustomBot")
|
|
51
|
+
puts "✓ HTM initialized with custom LLM configuration"
|
|
52
|
+
|
|
53
|
+
# Test the custom methods
|
|
54
|
+
embedding = HTM.embed("This is a test message")
|
|
55
|
+
puts "✓ Custom embedding generated: #{embedding.length} dimensions"
|
|
56
|
+
|
|
57
|
+
tags = HTM.extract_tags("PostgreSQL is a powerful database", existing_ontology: ['database:sql'])
|
|
58
|
+
puts "✓ Custom tags extracted: #{tags.join(', ')}"
|
|
59
|
+
|
|
60
|
+
# Example 3: Configure with Custom Class
|
|
61
|
+
puts "\n3. Custom Configuration with Service Object"
|
|
62
|
+
puts "-" * 50
|
|
63
|
+
|
|
64
|
+
# Define a custom LLM service class
|
|
65
|
+
class MyAppLLMService
|
|
66
|
+
def self.embed(text)
|
|
67
|
+
puts " → MyAppLLMService.embed called"
|
|
68
|
+
# Your application's embedding logic here
|
|
69
|
+
# Could integrate with LangChain, LlamaIndex, or custom infrastructure
|
|
70
|
+
Array.new(1024) { rand } # 1024-dimensional embeddings
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def self.extract_tags(text, ontology)
|
|
74
|
+
puts " → MyAppLLMService.extract_tags called"
|
|
75
|
+
# Your application's tag extraction logic here
|
|
76
|
+
['app:feature:memory', 'app:component:llm']
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
HTM.configure do |config|
|
|
81
|
+
config.embedding_generator = ->(text) { MyAppLLMService.embed(text) }
|
|
82
|
+
config.tag_extractor = ->(text, ontology) { MyAppLLMService.extract_tags(text, ontology) }
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
htm = HTM.new(robot_name: "ServiceBot")
|
|
86
|
+
puts "✓ HTM initialized with service object configuration"
|
|
87
|
+
|
|
88
|
+
embedding = HTM.embed("Another test message")
|
|
89
|
+
puts "✓ Service embedding generated: #{embedding.length} dimensions"
|
|
90
|
+
|
|
91
|
+
# Example 4: Mixed Configuration (Custom Embedding, Default Tags)
|
|
92
|
+
puts "\n4. Mixed Configuration (Custom + Default)"
|
|
93
|
+
puts "-" * 50
|
|
94
|
+
|
|
95
|
+
HTM.configure do |config|
|
|
96
|
+
# Use custom embedding
|
|
97
|
+
config.embedding_generator = ->(text) {
|
|
98
|
+
puts " → Using custom embedder"
|
|
99
|
+
Array.new(512) { rand }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
# Keep default tag extraction
|
|
103
|
+
# (Already set by default, but showing explicit control)
|
|
104
|
+
config.reset_to_defaults # Reset both
|
|
105
|
+
|
|
106
|
+
# Then override just embedding
|
|
107
|
+
config.embedding_generator = ->(text) {
|
|
108
|
+
puts " → Using custom embedder with default tagger"
|
|
109
|
+
Array.new(512) { rand }
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
htm = HTM.new(robot_name: "MixedBot")
|
|
114
|
+
puts "✓ HTM initialized with mixed configuration"
|
|
115
|
+
|
|
116
|
+
# Example 5: Configure Provider Settings for Defaults
|
|
117
|
+
puts "\n5. Configuring Default Provider Settings"
|
|
118
|
+
puts "-" * 50
|
|
119
|
+
|
|
120
|
+
HTM.configure do |config|
|
|
121
|
+
# Customize the default RubyLLM configuration
|
|
122
|
+
config.embedding_provider = :ollama
|
|
123
|
+
config.embedding_model = 'nomic-embed-text'
|
|
124
|
+
config.embedding_dimensions = 768
|
|
125
|
+
|
|
126
|
+
config.tag_provider = :ollama
|
|
127
|
+
config.tag_model = 'llama3'
|
|
128
|
+
|
|
129
|
+
config.ollama_url = ENV['OLLAMA_URL'] || 'http://localhost:11434'
|
|
130
|
+
|
|
131
|
+
# Reset to use these new settings with default implementations
|
|
132
|
+
config.reset_to_defaults
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
htm = HTM.new(robot_name: "ConfiguredDefaultBot")
|
|
136
|
+
puts "✓ HTM initialized with configured default settings"
|
|
137
|
+
puts " Embedding model: #{HTM.configuration.embedding_model}"
|
|
138
|
+
puts " Tag model: #{HTM.configuration.tag_model}"
|
|
139
|
+
puts " Ollama URL: #{HTM.configuration.ollama_url}"
|
|
140
|
+
|
|
141
|
+
# Example 6: Integration with HTM Operations
|
|
142
|
+
puts "\n6. Using Custom Configuration in HTM Operations"
|
|
143
|
+
puts "-" * 50
|
|
144
|
+
|
|
145
|
+
# Configure with test implementation
|
|
146
|
+
HTM.configure do |config|
|
|
147
|
+
config.embedding_generator = ->(text) {
|
|
148
|
+
puts " → Embedding: #{text[0..40]}..."
|
|
149
|
+
Array.new(768) { rand }
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
config.tag_extractor = ->(text, ontology) {
|
|
153
|
+
puts " → Tagging: #{text[0..40]}..."
|
|
154
|
+
['example:ruby:gem', 'memory:llm']
|
|
155
|
+
}
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
htm = HTM.new(robot_name: "IntegrationBot")
|
|
159
|
+
|
|
160
|
+
# Remember information - will use custom LLM configuration
|
|
161
|
+
puts "\nRemembering information in HTM..."
|
|
162
|
+
node_id = htm.remember(
|
|
163
|
+
"PostgreSQL with pgvector enables efficient vector similarity search",
|
|
164
|
+
source: 'user'
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
puts "✓ Information remembered with node_id: #{node_id}"
|
|
168
|
+
puts " Note: Embedding and LLM-generated tags will be processed asynchronously"
|
|
169
|
+
|
|
170
|
+
# The async jobs will call:
|
|
171
|
+
# - HTM.embed(content) for embedding generation
|
|
172
|
+
# - HTM.extract_tags(content, existing_ontology) for tag extraction
|
|
173
|
+
|
|
174
|
+
puts "\n" + "=" * 50
|
|
175
|
+
puts "Configuration Summary"
|
|
176
|
+
puts "=" * 50
|
|
177
|
+
puts "Applications can configure HTM by:"
|
|
178
|
+
puts "1. Using HTM.configure with a block"
|
|
179
|
+
puts "2. Providing embedding_generator callable (String → Array<Float>)"
|
|
180
|
+
puts "3. Providing tag_extractor callable (String, Array<String> → Array<String>)"
|
|
181
|
+
puts "4. Or using sensible defaults with RubyLLM + Ollama"
|
|
182
|
+
puts "\nHTM delegates all LLM operations to these configured methods,"
|
|
183
|
+
puts "allowing complete flexibility in LLM infrastructure."
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Example Application Rakefile
|
|
2
|
+
#
|
|
3
|
+
# This demonstrates how to integrate HTM rake tasks into your application.
|
|
4
|
+
# Simply require 'htm/tasks' and all database management tasks become available.
|
|
5
|
+
|
|
6
|
+
require 'bundler/setup'
|
|
7
|
+
|
|
8
|
+
# Load HTM database tasks - that's it!
|
|
9
|
+
require 'htm/tasks'
|
|
10
|
+
|
|
11
|
+
# Your application's custom tasks
|
|
12
|
+
namespace :app do
|
|
13
|
+
desc "Start the example application"
|
|
14
|
+
task :start do
|
|
15
|
+
puts "\n=== Starting Example HTM Application ==="
|
|
16
|
+
puts "Database configured: #{ENV['HTM_DBURL'] ? 'Yes' : 'No'}"
|
|
17
|
+
puts "\nRun 'rake -T' to see all available tasks"
|
|
18
|
+
puts "Run 'rake -T htm:db' to see HTM database tasks\n\n"
|
|
19
|
+
|
|
20
|
+
# Your app code here
|
|
21
|
+
require_relative 'app'
|
|
22
|
+
ExampleApp.run
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
desc "Bootstrap application (setup database + start)"
|
|
26
|
+
task :bootstrap => ['htm:db:setup', :start]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
namespace :dev do
|
|
30
|
+
desc "Reset database for development (WARNING: destructive!)"
|
|
31
|
+
task :reset => ['htm:db:reset', 'htm:db:seed']
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Default task
|
|
35
|
+
task default: 'app:start'
|
|
36
|
+
|
|
37
|
+
# Show usage help
|
|
38
|
+
desc "Show usage help"
|
|
39
|
+
task :help do
|
|
40
|
+
puts <<~HELP
|
|
41
|
+
|
|
42
|
+
Example HTM Application - Available Commands
|
|
43
|
+
============================================
|
|
44
|
+
|
|
45
|
+
Setup & Start:
|
|
46
|
+
rake app:bootstrap Bootstrap app (setup DB + start)
|
|
47
|
+
rake app:start Start the application (default)
|
|
48
|
+
|
|
49
|
+
Database Management:
|
|
50
|
+
rake htm:db:setup Set up HTM database schema
|
|
51
|
+
rake htm:db:migrate Run pending migrations
|
|
52
|
+
rake htm:db:status Show migration status
|
|
53
|
+
rake htm:db:info Show database information
|
|
54
|
+
rake htm:db:test Test database connection
|
|
55
|
+
rake htm:db:console Open PostgreSQL console
|
|
56
|
+
rake htm:db:seed Seed with sample data
|
|
57
|
+
|
|
58
|
+
Development:
|
|
59
|
+
rake dev:reset Reset database (drop/create/seed)
|
|
60
|
+
|
|
61
|
+
Destructive (Use with caution!):
|
|
62
|
+
rake htm:db:drop Drop all HTM tables
|
|
63
|
+
rake htm:db:reset Drop and recreate database
|
|
64
|
+
|
|
65
|
+
Environment:
|
|
66
|
+
export HTM_DBURL="postgresql://user:pass@host:port/dbname"
|
|
67
|
+
|
|
68
|
+
See docs/using_rake_tasks_in_your_app.md for more information.
|
|
69
|
+
|
|
70
|
+
HELP
|
|
71
|
+
end
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# Example HTM Application
|
|
3
|
+
#
|
|
4
|
+
# This demonstrates a simple application using the HTM gem with full RubyLLM integration.
|
|
5
|
+
|
|
6
|
+
require_relative '../../lib/htm'
|
|
7
|
+
require 'ruby_llm'
|
|
8
|
+
require 'logger'
|
|
9
|
+
|
|
10
|
+
class ExampleApp
|
|
11
|
+
def self.run
|
|
12
|
+
puts "\n=== HTM Full-Featured Example Application ==="
|
|
13
|
+
puts "\nChecking database connection..."
|
|
14
|
+
|
|
15
|
+
# Check if database is configured
|
|
16
|
+
config = HTM::Database.default_config
|
|
17
|
+
unless config
|
|
18
|
+
puts "\n⚠ Database not configured!"
|
|
19
|
+
puts "Set HTM_DBURL environment variable:"
|
|
20
|
+
puts " export HTM_DBURL='postgresql://user:pass@host:port/dbname'"
|
|
21
|
+
puts "\nOr run: rake app:bootstrap"
|
|
22
|
+
return
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
puts "✓ Database configured: #{config[:dbname]} @ #{config[:host]}"
|
|
26
|
+
|
|
27
|
+
# Configure HTM with RubyLLM for embeddings and tag generation
|
|
28
|
+
puts "\nConfiguring HTM with RubyLLM..."
|
|
29
|
+
HTM.configure do |c|
|
|
30
|
+
# Configure logger
|
|
31
|
+
c.logger = Logger.new($stdout)
|
|
32
|
+
c.logger.level = Logger::INFO
|
|
33
|
+
|
|
34
|
+
# Configure embedding generation (using Ollama)
|
|
35
|
+
c.embedding_provider = :ollama
|
|
36
|
+
c.embedding_model = 'nomic-embed-text'
|
|
37
|
+
c.embedding_dimensions = 768
|
|
38
|
+
c.ollama_url = ENV['OLLAMA_URL'] || 'http://localhost:11434'
|
|
39
|
+
|
|
40
|
+
# Configure tag extraction (using Ollama - using smaller/faster model)
|
|
41
|
+
c.tag_provider = :ollama
|
|
42
|
+
c.tag_model = 'gemma3' # Smaller model (3.3GB) for faster tag generation
|
|
43
|
+
|
|
44
|
+
# Apply default implementations
|
|
45
|
+
c.reset_to_defaults
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
puts "✓ Configured with Ollama:"
|
|
49
|
+
puts " - Embeddings: #{HTM.configuration.embedding_model}"
|
|
50
|
+
puts " - Tags: #{HTM.configuration.tag_model}"
|
|
51
|
+
puts " - Ollama URL: #{HTM.configuration.ollama_url}"
|
|
52
|
+
|
|
53
|
+
# Check if Ollama is running
|
|
54
|
+
puts "\nChecking Ollama connection..."
|
|
55
|
+
begin
|
|
56
|
+
require 'net/http'
|
|
57
|
+
uri = URI(HTM.configuration.ollama_url)
|
|
58
|
+
response = Net::HTTP.get_response(uri)
|
|
59
|
+
puts "✓ Ollama is running"
|
|
60
|
+
rescue StandardError => e
|
|
61
|
+
puts "⚠ Warning: Cannot connect to Ollama (#{e.message})"
|
|
62
|
+
puts " Embeddings and tags will not be generated."
|
|
63
|
+
puts " Install Ollama: https://ollama.ai"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Create HTM instance
|
|
67
|
+
puts "\nInitializing HTM..."
|
|
68
|
+
htm = HTM.new(robot_name: "Example App Robot")
|
|
69
|
+
|
|
70
|
+
# Remember some conversation (simulating a conversation)
|
|
71
|
+
puts "\nRemembering example conversation..."
|
|
72
|
+
puts "(Tags will be auto-extracted by LLM in background)"
|
|
73
|
+
|
|
74
|
+
node_1 = htm.remember(
|
|
75
|
+
"HTM provides intelligent memory management for LLM-based applications",
|
|
76
|
+
source: "assistant"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
node_2 = htm.remember(
|
|
80
|
+
"The two-tier architecture includes working memory and long-term storage",
|
|
81
|
+
source: "assistant"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
node_3 = htm.remember(
|
|
85
|
+
"Can you explain how the working memory eviction algorithm works?",
|
|
86
|
+
source: "user"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
puts "✓ Remembered 3 conversation messages (nodes #{node_1}, #{node_2}, #{node_3})"
|
|
90
|
+
puts " Embeddings and tags are being generated asynchronously..."
|
|
91
|
+
|
|
92
|
+
# Wait for background jobs to complete
|
|
93
|
+
# Note: Tag generation with LLM can take 10-15 seconds depending on model size
|
|
94
|
+
puts "\nWaiting for background jobs to complete (15 seconds)..."
|
|
95
|
+
puts "(Embeddings are fast, but tag generation requires LLM inference)"
|
|
96
|
+
sleep 15
|
|
97
|
+
|
|
98
|
+
# Check what was generated
|
|
99
|
+
puts "\n--- Generated Tags ---"
|
|
100
|
+
[node_1, node_2, node_3].each do |node_id|
|
|
101
|
+
node = HTM::Models::Node.includes(:tags).find(node_id)
|
|
102
|
+
if node.tags.any?
|
|
103
|
+
puts "Node #{node_id}:"
|
|
104
|
+
node.tags.each { |tag| puts " - #{tag.name}" }
|
|
105
|
+
else
|
|
106
|
+
puts "Node #{node_id}: (no tags yet)"
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Check embeddings
|
|
111
|
+
puts "\n--- Embedding Status ---"
|
|
112
|
+
[node_1, node_2, node_3].each do |node_id|
|
|
113
|
+
node = HTM::Models::Node.find(node_id)
|
|
114
|
+
if node.embedding
|
|
115
|
+
dimensions = node.embedding.is_a?(Array) ? node.embedding.size : node.embedding_dimension
|
|
116
|
+
status = "✓ Generated (#{dimensions} dimensions)"
|
|
117
|
+
else
|
|
118
|
+
status = "⏳ Pending"
|
|
119
|
+
end
|
|
120
|
+
puts "Node #{node_id}: #{status}"
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# Demonstrate different recall strategies
|
|
124
|
+
puts "\n--- Recall Strategies Comparison ---"
|
|
125
|
+
|
|
126
|
+
# 1. Full-text search (doesn't require embeddings)
|
|
127
|
+
puts "\n1. Full-text Search for 'memory':"
|
|
128
|
+
fulltext_memories = htm.recall(
|
|
129
|
+
"memory",
|
|
130
|
+
timeframe: (Time.now - 3600)..Time.now,
|
|
131
|
+
strategy: :fulltext,
|
|
132
|
+
limit: 3
|
|
133
|
+
)
|
|
134
|
+
puts "Found #{fulltext_memories.length} memories:"
|
|
135
|
+
fulltext_memories.each do |memory|
|
|
136
|
+
puts " - Node #{memory['id']}: #{memory['content'][0..60]}..."
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# 2. Vector search (requires embeddings)
|
|
140
|
+
puts "\n2. Vector Search for 'intelligent memory system':"
|
|
141
|
+
begin
|
|
142
|
+
vector_memories = htm.recall(
|
|
143
|
+
"intelligent memory system",
|
|
144
|
+
timeframe: (Time.now - 3600)..Time.now,
|
|
145
|
+
strategy: :vector,
|
|
146
|
+
limit: 3
|
|
147
|
+
)
|
|
148
|
+
puts "Found #{vector_memories.length} memories:"
|
|
149
|
+
vector_memories.each do |memory|
|
|
150
|
+
puts " - Node #{memory['id']}: #{memory['content'][0..60]}..."
|
|
151
|
+
end
|
|
152
|
+
rescue StandardError => e
|
|
153
|
+
puts " ⚠ Vector search error: #{e.message}"
|
|
154
|
+
puts " #{e.class}: #{e.backtrace.first}"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# 3. Hybrid search (combines both)
|
|
158
|
+
puts "\n3. Hybrid Search for 'working memory architecture':"
|
|
159
|
+
begin
|
|
160
|
+
hybrid_memories = htm.recall(
|
|
161
|
+
"working memory architecture",
|
|
162
|
+
timeframe: (Time.now - 3600)..Time.now,
|
|
163
|
+
strategy: :hybrid,
|
|
164
|
+
limit: 3
|
|
165
|
+
)
|
|
166
|
+
puts "Found #{hybrid_memories.length} memories:"
|
|
167
|
+
hybrid_memories.each do |memory|
|
|
168
|
+
puts " - Node #{memory['id']}: #{memory['content'][0..60]}..."
|
|
169
|
+
end
|
|
170
|
+
rescue StandardError => e
|
|
171
|
+
puts " ⚠ Hybrid search error: #{e.message}"
|
|
172
|
+
puts " #{e.class}: #{e.backtrace.first}"
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Summary
|
|
176
|
+
puts "\n" + "="*60
|
|
177
|
+
puts "✓ Demo Complete!"
|
|
178
|
+
puts "="*60
|
|
179
|
+
puts "\nThe HTM API provides 3 core methods:"
|
|
180
|
+
puts " 1. htm.remember(content, source:)"
|
|
181
|
+
puts " - Stores information in long-term memory"
|
|
182
|
+
puts " - Adds to working memory for immediate use"
|
|
183
|
+
puts " - Generates embeddings and tags in background"
|
|
184
|
+
puts ""
|
|
185
|
+
puts " 2. htm.recall(timeframe:, topic:, strategy:, limit:)"
|
|
186
|
+
puts " - Retrieves relevant memories"
|
|
187
|
+
puts " - Strategies: :fulltext, :vector, :hybrid"
|
|
188
|
+
puts " - Results added to working memory"
|
|
189
|
+
puts ""
|
|
190
|
+
puts " 3. htm.forget(node_id, confirm: :confirmed)"
|
|
191
|
+
puts " - Permanently deletes a memory node"
|
|
192
|
+
puts " - Requires explicit confirmation"
|
|
193
|
+
puts ""
|
|
194
|
+
puts "Background Features:"
|
|
195
|
+
puts " - Automatic embedding generation (#{HTM.configuration.embedding_model})"
|
|
196
|
+
puts " - Automatic hierarchical tag extraction (#{HTM.configuration.tag_model})"
|
|
197
|
+
puts " - Token counting for context management"
|
|
198
|
+
puts " - Multi-robot shared memory (hive mind)"
|
|
199
|
+
puts ""
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# Run directly if called as script
|
|
204
|
+
if __FILE__ == $0
|
|
205
|
+
ExampleApp.run
|
|
206
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
source 'https://rubygems.org'
|
|
4
|
+
|
|
5
|
+
# Web framework
|
|
6
|
+
gem 'sinatra', '~> 3.0'
|
|
7
|
+
gem 'puma', '~> 6.0'
|
|
8
|
+
|
|
9
|
+
# Background jobs
|
|
10
|
+
gem 'sidekiq', '~> 7.0'
|
|
11
|
+
gem 'redis', '~> 5.0'
|
|
12
|
+
|
|
13
|
+
# HTM (use local development version)
|
|
14
|
+
gem 'htm', path: '../..'
|
|
15
|
+
|
|
16
|
+
# JSON handling
|
|
17
|
+
gem 'multi_json'
|
|
18
|
+
|
|
19
|
+
group :development do
|
|
20
|
+
gem 'rerun' # Auto-reload on file changes
|
|
21
|
+
end
|