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,93 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Basic usage example for HTM
|
|
5
|
+
#
|
|
6
|
+
# Prerequisites:
|
|
7
|
+
# 1. Source environment variables: source ~/.bashrc__tiger
|
|
8
|
+
# 2. Initialize database schema: ruby -r ./lib/htm -e "HTM::Database.setup"
|
|
9
|
+
# 3. Install dependencies: bundle install
|
|
10
|
+
|
|
11
|
+
require_relative '../lib/htm'
|
|
12
|
+
|
|
13
|
+
puts "HTM Basic Usage Example"
|
|
14
|
+
puts "=" * 60
|
|
15
|
+
|
|
16
|
+
# Check environment
|
|
17
|
+
unless ENV['HTM_DBURL']
|
|
18
|
+
puts "ERROR: HTM_DBURL not set. Please run: source ~/.bashrc__tiger"
|
|
19
|
+
exit 1
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
begin
|
|
23
|
+
# Configure HTM globally (uses RubyLLM with Ollama by default)
|
|
24
|
+
puts "\n1. Configuring HTM with Ollama provider..."
|
|
25
|
+
HTM.configure do |config|
|
|
26
|
+
config.embedding_provider = :ollama
|
|
27
|
+
config.embedding_model = 'nomic-embed-text'
|
|
28
|
+
config.embedding_dimensions = 768
|
|
29
|
+
config.tag_provider = :ollama
|
|
30
|
+
config.tag_model = 'llama3'
|
|
31
|
+
config.reset_to_defaults # Apply settings
|
|
32
|
+
end
|
|
33
|
+
puts "✓ HTM configured with Ollama provider"
|
|
34
|
+
|
|
35
|
+
# Initialize HTM for 'Code Helper' robot
|
|
36
|
+
puts "\n2. Initializing HTM for 'Code Helper' robot..."
|
|
37
|
+
htm = HTM.new(
|
|
38
|
+
robot_name: "Code Helper",
|
|
39
|
+
working_memory_size: 128_000
|
|
40
|
+
)
|
|
41
|
+
puts "✓ HTM initialized"
|
|
42
|
+
puts " Robot ID: #{htm.robot_id}"
|
|
43
|
+
puts " Robot Name: #{htm.robot_name}"
|
|
44
|
+
puts " Embedding Service: Ollama (#{HTM.configuration.embedding_model})"
|
|
45
|
+
|
|
46
|
+
# Remember some information
|
|
47
|
+
puts "\n3. Remembering information..."
|
|
48
|
+
|
|
49
|
+
node_id_1 = htm.remember(
|
|
50
|
+
"We decided to use PostgreSQL for HTM storage because it provides excellent time-series optimization and native vector search with pgvector.",
|
|
51
|
+
source: "architect"
|
|
52
|
+
)
|
|
53
|
+
puts "✓ Remembered decision about database choice (node #{node_id_1})"
|
|
54
|
+
|
|
55
|
+
node_id_2 = htm.remember(
|
|
56
|
+
"We chose RAG (Retrieval-Augmented Generation) for memory recall, combining temporal filtering with semantic vector search.",
|
|
57
|
+
source: "architect"
|
|
58
|
+
)
|
|
59
|
+
puts "✓ Remembered decision about RAG approach (node #{node_id_2})"
|
|
60
|
+
|
|
61
|
+
node_id_3 = htm.remember(
|
|
62
|
+
"The user's name is Dewayne and they prefer using debug_me for debugging instead of puts.",
|
|
63
|
+
source: "system"
|
|
64
|
+
)
|
|
65
|
+
puts "✓ Remembered fact about user preferences (node #{node_id_3})"
|
|
66
|
+
|
|
67
|
+
# Sleep briefly to allow async embedding/tag jobs to start
|
|
68
|
+
sleep 0.5
|
|
69
|
+
|
|
70
|
+
# Demonstrate recall
|
|
71
|
+
puts "\n4. Recalling memories about 'database'..."
|
|
72
|
+
memories = htm.recall(
|
|
73
|
+
"database",
|
|
74
|
+
timeframe: (Time.now - 3600)..Time.now, # Last hour
|
|
75
|
+
limit: 5
|
|
76
|
+
)
|
|
77
|
+
puts "✓ Found #{memories.length} memories"
|
|
78
|
+
memories.each do |memory|
|
|
79
|
+
puts " - Node #{memory['id']}: #{memory['content'][0..60]}..."
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
puts "\n" + "=" * 60
|
|
83
|
+
puts "✓ Example completed successfully!"
|
|
84
|
+
puts "\nThe HTM API provides 3 core methods:"
|
|
85
|
+
puts " - htm.remember(content, source:) - Store information"
|
|
86
|
+
puts " - htm.recall(timeframe:, topic:, ...) - Retrieve memories"
|
|
87
|
+
puts " - htm.forget(node_id, confirm:) - Delete a memory"
|
|
88
|
+
|
|
89
|
+
rescue => e
|
|
90
|
+
puts "\n✗ Error: #{e.message}"
|
|
91
|
+
puts e.backtrace.first(5).join("\n")
|
|
92
|
+
exit 1
|
|
93
|
+
end
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# HTM CLI Application Example
|
|
2
|
+
|
|
3
|
+
This example demonstrates using HTM in a command-line application with synchronous job execution.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Synchronous Execution**: Uses `:inline` job backend for immediate embedding/tag generation
|
|
8
|
+
- **Interactive Interface**: Command-line REPL for remembering and recalling information
|
|
9
|
+
- **Progress Feedback**: Real-time feedback on operations
|
|
10
|
+
- **Database Persistence**: All memories stored in PostgreSQL
|
|
11
|
+
- **Full HTM Features**: Vector search, tag extraction, hybrid search
|
|
12
|
+
|
|
13
|
+
## Prerequisites
|
|
14
|
+
|
|
15
|
+
1. **PostgreSQL Database**
|
|
16
|
+
```bash
|
|
17
|
+
# Set database connection URL
|
|
18
|
+
export HTM_DBURL='postgresql://user:pass@host:port/dbname'
|
|
19
|
+
|
|
20
|
+
# Or use your existing config
|
|
21
|
+
source ~/.bashrc__tiger
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
2. **Ollama** (recommended but optional)
|
|
25
|
+
```bash
|
|
26
|
+
# Install Ollama
|
|
27
|
+
curl https://ollama.ai/install.sh | sh
|
|
28
|
+
|
|
29
|
+
# Pull models
|
|
30
|
+
ollama pull nomic-embed-text # For embeddings
|
|
31
|
+
ollama pull llama3 # For tag extraction
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
3. **Ruby Dependencies**
|
|
35
|
+
```bash
|
|
36
|
+
# From HTM root directory
|
|
37
|
+
bundle install
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Usage
|
|
41
|
+
|
|
42
|
+
### Run the CLI
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# Make executable
|
|
46
|
+
chmod +x htm_cli.rb
|
|
47
|
+
|
|
48
|
+
# Run
|
|
49
|
+
./htm_cli.rb
|
|
50
|
+
# or
|
|
51
|
+
ruby htm_cli.rb
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Commands
|
|
55
|
+
|
|
56
|
+
**Store Information**
|
|
57
|
+
```
|
|
58
|
+
htm> remember PostgreSQL is great for time-series data
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**Search Memories**
|
|
62
|
+
```
|
|
63
|
+
htm> recall PostgreSQL
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**View Statistics**
|
|
67
|
+
```
|
|
68
|
+
htm> stats
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Show Help**
|
|
72
|
+
```
|
|
73
|
+
htm> help
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**Exit**
|
|
77
|
+
```
|
|
78
|
+
htm> exit
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## How It Works
|
|
82
|
+
|
|
83
|
+
### Synchronous Job Execution
|
|
84
|
+
|
|
85
|
+
Unlike web applications, CLI apps use `:inline` job backend:
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
HTM.configure do |config|
|
|
89
|
+
config.job_backend = :inline # Execute jobs synchronously
|
|
90
|
+
end
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
This means:
|
|
94
|
+
- `remember()` waits for embeddings and tags to be generated
|
|
95
|
+
- Immediate feedback on completion
|
|
96
|
+
- Simpler debugging and testing
|
|
97
|
+
- No background job infrastructure needed
|
|
98
|
+
|
|
99
|
+
### Job Backend Comparison
|
|
100
|
+
|
|
101
|
+
| Backend | CLI | Web Apps | When to Use |
|
|
102
|
+
|---------|-----|----------|-------------|
|
|
103
|
+
| `:inline` | ✅ | ❌ | CLI tools, tests |
|
|
104
|
+
| `:thread` | ⚠️ | ⚠️ | Simple standalone apps |
|
|
105
|
+
| `:sidekiq` | ❌ | ✅ | Sinatra, microservices |
|
|
106
|
+
| `:active_job` | ❌ | ✅ | Rails applications |
|
|
107
|
+
|
|
108
|
+
## Example Session
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
$ ruby htm_cli.rb
|
|
112
|
+
|
|
113
|
+
============================================================
|
|
114
|
+
HTM CLI - Hierarchical Temporary Memory Assistant
|
|
115
|
+
============================================================
|
|
116
|
+
|
|
117
|
+
Job Backend: inline (synchronous execution)
|
|
118
|
+
Robot: cli_assistant
|
|
119
|
+
|
|
120
|
+
Commands:
|
|
121
|
+
remember <text> - Store information
|
|
122
|
+
recall <topic> - Search memories
|
|
123
|
+
stats - Show memory statistics
|
|
124
|
+
help - Show this help
|
|
125
|
+
exit - Quit
|
|
126
|
+
|
|
127
|
+
============================================================
|
|
128
|
+
|
|
129
|
+
htm> remember PostgreSQL with pgvector enables semantic search
|
|
130
|
+
|
|
131
|
+
Remembering: "PostgreSQL with pgvector enables semantic search"
|
|
132
|
+
Processing...
|
|
133
|
+
[✓] Stored as node 1 (1243.56ms)
|
|
134
|
+
Embedding: 768 dimensions
|
|
135
|
+
Tags: database:postgresql, search:semantic, ai:vector-search
|
|
136
|
+
|
|
137
|
+
htm> remember TimescaleDB is built on PostgreSQL for time-series
|
|
138
|
+
|
|
139
|
+
Remembering: "TimescaleDB is built on PostgreSQL for time-series"
|
|
140
|
+
Processing...
|
|
141
|
+
[✓] Stored as node 2 (1189.32ms)
|
|
142
|
+
Embedding: 768 dimensions
|
|
143
|
+
Tags: database:postgresql, database:timescaledb, time-series
|
|
144
|
+
|
|
145
|
+
htm> recall PostgreSQL
|
|
146
|
+
|
|
147
|
+
Searching for: "PostgreSQL"
|
|
148
|
+
Strategy: hybrid (vector + fulltext)
|
|
149
|
+
[✓] Found 2 memories (45.67ms)
|
|
150
|
+
|
|
151
|
+
1. Node 1 (cli_user)
|
|
152
|
+
Created: 2025-11-09 14:23:15 UTC
|
|
153
|
+
Content: PostgreSQL with pgvector enables semantic search
|
|
154
|
+
Tags: database:postgresql, search:semantic, ai:vector-search
|
|
155
|
+
|
|
156
|
+
2. Node 2 (cli_user)
|
|
157
|
+
Created: 2025-11-09 14:23:42 UTC
|
|
158
|
+
Content: TimescaleDB is built on PostgreSQL for time-series
|
|
159
|
+
Tags: database:postgresql, database:timescaledb, time-series
|
|
160
|
+
|
|
161
|
+
htm> stats
|
|
162
|
+
|
|
163
|
+
Memory Statistics:
|
|
164
|
+
|
|
165
|
+
Nodes:
|
|
166
|
+
Total: 2
|
|
167
|
+
With embeddings: 2 (100.0%)
|
|
168
|
+
With tags: 2 (100.0%)
|
|
169
|
+
|
|
170
|
+
Tags:
|
|
171
|
+
Total: 5
|
|
172
|
+
Average per node: 2.5
|
|
173
|
+
|
|
174
|
+
Robots:
|
|
175
|
+
Total: 1
|
|
176
|
+
|
|
177
|
+
Current Robot (cli_assistant):
|
|
178
|
+
Nodes: 2
|
|
179
|
+
|
|
180
|
+
htm> exit
|
|
181
|
+
|
|
182
|
+
Goodbye!
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Configuration Options
|
|
186
|
+
|
|
187
|
+
### Custom Logger
|
|
188
|
+
|
|
189
|
+
```ruby
|
|
190
|
+
HTM.configure do |config|
|
|
191
|
+
config.logger = Logger.new('htm_cli.log')
|
|
192
|
+
config.logger.level = Logger::DEBUG
|
|
193
|
+
end
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Custom Models
|
|
197
|
+
|
|
198
|
+
```ruby
|
|
199
|
+
HTM.configure do |config|
|
|
200
|
+
config.embedding_model = 'custom-embedding-model'
|
|
201
|
+
config.tag_model = 'custom-tag-model'
|
|
202
|
+
end
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Timeouts
|
|
206
|
+
|
|
207
|
+
```ruby
|
|
208
|
+
HTM.configure do |config|
|
|
209
|
+
config.embedding_timeout = 60 # 1 minute
|
|
210
|
+
config.tag_timeout = 120 # 2 minutes
|
|
211
|
+
end
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Performance Considerations
|
|
215
|
+
|
|
216
|
+
### Synchronous Execution Trade-offs
|
|
217
|
+
|
|
218
|
+
**Pros:**
|
|
219
|
+
- Immediate feedback
|
|
220
|
+
- Simple error handling
|
|
221
|
+
- No background infrastructure needed
|
|
222
|
+
- Predictable timing
|
|
223
|
+
|
|
224
|
+
**Cons:**
|
|
225
|
+
- Slower user-facing operations (1-3 seconds per remember)
|
|
226
|
+
- Blocks on LLM API calls
|
|
227
|
+
- Not suitable for high-throughput scenarios
|
|
228
|
+
|
|
229
|
+
### Optimization Tips
|
|
230
|
+
|
|
231
|
+
1. **Batch Operations**: Group multiple `remember()` calls
|
|
232
|
+
2. **Caching**: Use query cache for repeated searches
|
|
233
|
+
3. **Faster Models**: Use smaller embedding models for CLI
|
|
234
|
+
4. **Selective Features**: Disable tags if not needed
|
|
235
|
+
|
|
236
|
+
```ruby
|
|
237
|
+
# Disable tag generation for faster CLI
|
|
238
|
+
HTM.configure do |config|
|
|
239
|
+
config.tag_extractor = ->(_text, _ontology) { [] }
|
|
240
|
+
end
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Troubleshooting
|
|
244
|
+
|
|
245
|
+
### Database Connection Errors
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
# Verify database URL
|
|
249
|
+
echo $HTM_DBURL
|
|
250
|
+
|
|
251
|
+
# Test connection
|
|
252
|
+
psql $HTM_DBURL -c "SELECT version();"
|
|
253
|
+
|
|
254
|
+
# Initialize schema if needed
|
|
255
|
+
cd ../.. && rake db_setup
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Ollama Connection Errors
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
# Check if Ollama is running
|
|
262
|
+
curl http://localhost:11434/api/version
|
|
263
|
+
|
|
264
|
+
# Start Ollama
|
|
265
|
+
ollama serve
|
|
266
|
+
|
|
267
|
+
# Verify models are pulled
|
|
268
|
+
ollama list
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Slow Performance
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
# Use faster models
|
|
275
|
+
export EMBEDDING_MODEL=all-minilm
|
|
276
|
+
export TAG_MODEL=gemma2:2b
|
|
277
|
+
|
|
278
|
+
# Or disable features
|
|
279
|
+
# (modify htm_cli.rb to skip tag generation)
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Extending the CLI
|
|
283
|
+
|
|
284
|
+
### Add New Commands
|
|
285
|
+
|
|
286
|
+
```ruby
|
|
287
|
+
# In htm_cli.rb, add to handle_command:
|
|
288
|
+
when 'export'
|
|
289
|
+
handle_export(args)
|
|
290
|
+
|
|
291
|
+
# Implement handler:
|
|
292
|
+
def handle_export(filename)
|
|
293
|
+
nodes = HTM::Models::Node.all
|
|
294
|
+
File.write(filename, nodes.to_json)
|
|
295
|
+
puts "[✓] Exported #{nodes.count} nodes to #{filename}"
|
|
296
|
+
end
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Custom Search Strategies
|
|
300
|
+
|
|
301
|
+
```ruby
|
|
302
|
+
def handle_recall(topic)
|
|
303
|
+
# Use different strategies
|
|
304
|
+
vector_results = @htm.recall(topic, strategy: :vector)
|
|
305
|
+
fulltext_results = @htm.recall(topic, strategy: :fulltext)
|
|
306
|
+
hybrid_results = @htm.recall(topic, strategy: :hybrid)
|
|
307
|
+
|
|
308
|
+
# Compare and choose best
|
|
309
|
+
end
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
## See Also
|
|
313
|
+
|
|
314
|
+
- [HTM README](../../README.md) - Main documentation
|
|
315
|
+
- [Sinatra Example](../sinatra_app/README.md) - Web application example
|
|
316
|
+
- [Rails Example](../rails_app/README.md) - Rails integration
|
|
317
|
+
- [Job Backends Documentation](../../docs/job_backends.md) - Job backend guide
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# HTM CLI Application Example
|
|
5
|
+
#
|
|
6
|
+
# Demonstrates using HTM in a command-line application with:
|
|
7
|
+
# - Synchronous job execution (inline mode)
|
|
8
|
+
# - Interactive command interface
|
|
9
|
+
# - Progress feedback
|
|
10
|
+
# - Database persistence
|
|
11
|
+
#
|
|
12
|
+
# Usage:
|
|
13
|
+
# ruby htm_cli.rb
|
|
14
|
+
#
|
|
15
|
+
# Environment:
|
|
16
|
+
# HTM_DBURL - PostgreSQL connection URL (required)
|
|
17
|
+
# OLLAMA_URL - Ollama server URL (default: http://localhost:11434)
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
require_relative '../../lib/htm'
|
|
21
|
+
require 'io/console'
|
|
22
|
+
|
|
23
|
+
class HTMCli
|
|
24
|
+
def initialize
|
|
25
|
+
# Configure HTM for CLI usage
|
|
26
|
+
HTM.configure do |config|
|
|
27
|
+
# Use inline mode for synchronous execution
|
|
28
|
+
config.job_backend = :inline
|
|
29
|
+
|
|
30
|
+
# CLI-friendly logging
|
|
31
|
+
config.logger.level = Logger::INFO
|
|
32
|
+
config.logger.formatter = proc do |severity, datetime, progname, msg|
|
|
33
|
+
case severity
|
|
34
|
+
when 'INFO'
|
|
35
|
+
"[✓] #{msg}\n"
|
|
36
|
+
when 'WARN'
|
|
37
|
+
"[⚠] #{msg}\n"
|
|
38
|
+
when 'ERROR'
|
|
39
|
+
"[✗] #{msg}\n"
|
|
40
|
+
else
|
|
41
|
+
"[•] #{msg}\n"
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Initialize HTM instance
|
|
47
|
+
@htm = HTM.new(robot_name: "cli_assistant")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def run
|
|
51
|
+
puts
|
|
52
|
+
puts "=" * 60
|
|
53
|
+
puts "HTM CLI - Hierarchical Temporary Memory Assistant"
|
|
54
|
+
puts "=" * 60
|
|
55
|
+
puts
|
|
56
|
+
puts "Job Backend: #{HTM.configuration.job_backend} (synchronous execution)"
|
|
57
|
+
puts "Robot: #{@htm.robot_name}"
|
|
58
|
+
puts
|
|
59
|
+
puts "Commands:"
|
|
60
|
+
puts " remember <text> - Store information"
|
|
61
|
+
puts " recall <topic> - Search memories"
|
|
62
|
+
puts " stats - Show memory statistics"
|
|
63
|
+
puts " help - Show this help"
|
|
64
|
+
puts " exit - Quit"
|
|
65
|
+
puts
|
|
66
|
+
puts "=" * 60
|
|
67
|
+
puts
|
|
68
|
+
|
|
69
|
+
loop do
|
|
70
|
+
print "\nhtm> "
|
|
71
|
+
input = gets&.chomp
|
|
72
|
+
break if input.nil? || input == 'exit'
|
|
73
|
+
|
|
74
|
+
handle_command(input)
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
puts "\nGoodbye!"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
def handle_command(input)
|
|
83
|
+
return if input.empty?
|
|
84
|
+
|
|
85
|
+
parts = input.split(' ', 2)
|
|
86
|
+
command = parts[0]
|
|
87
|
+
args = parts[1]
|
|
88
|
+
|
|
89
|
+
case command
|
|
90
|
+
when 'remember'
|
|
91
|
+
handle_remember(args)
|
|
92
|
+
when 'recall'
|
|
93
|
+
handle_recall(args)
|
|
94
|
+
when 'stats'
|
|
95
|
+
handle_stats
|
|
96
|
+
when 'help'
|
|
97
|
+
handle_help
|
|
98
|
+
else
|
|
99
|
+
puts "Unknown command: #{command}. Type 'help' for available commands."
|
|
100
|
+
end
|
|
101
|
+
rescue StandardError => e
|
|
102
|
+
puts "[✗] Error: #{e.message}"
|
|
103
|
+
puts " #{e.class}: #{e.backtrace.first}"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def handle_remember(text)
|
|
107
|
+
unless text && !text.empty?
|
|
108
|
+
puts "Usage: remember <text>"
|
|
109
|
+
return
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
puts "\nRemembering: \"#{text}\""
|
|
113
|
+
puts "Processing..."
|
|
114
|
+
|
|
115
|
+
start_time = Time.now
|
|
116
|
+
node_id = @htm.remember(text, source: 'cli_user')
|
|
117
|
+
duration = ((Time.now - start_time) * 1000).round(2)
|
|
118
|
+
|
|
119
|
+
puts "[✓] Stored as node #{node_id} (#{duration}ms)"
|
|
120
|
+
|
|
121
|
+
# Show what was generated (inline mode, so already complete)
|
|
122
|
+
node = HTM::Models::Node.includes(:tags).find(node_id)
|
|
123
|
+
|
|
124
|
+
if node.embedding
|
|
125
|
+
puts " Embedding: #{node.embedding_dimension} dimensions"
|
|
126
|
+
else
|
|
127
|
+
puts " Embedding: Not generated"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
if node.tags.any?
|
|
131
|
+
puts " Tags: #{node.tags.map(&:name).join(', ')}"
|
|
132
|
+
else
|
|
133
|
+
puts " Tags: None"
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def handle_recall(topic)
|
|
138
|
+
unless topic && !topic.empty?
|
|
139
|
+
puts "Usage: recall <topic>"
|
|
140
|
+
return
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
puts "\nSearching for: \"#{topic}\""
|
|
144
|
+
puts "Strategy: hybrid (vector + fulltext)"
|
|
145
|
+
|
|
146
|
+
start_time = Time.now
|
|
147
|
+
memories = @htm.recall(
|
|
148
|
+
topic,
|
|
149
|
+
limit: 10,
|
|
150
|
+
strategy: :hybrid,
|
|
151
|
+
raw: true
|
|
152
|
+
)
|
|
153
|
+
duration = ((Time.now - start_time) * 1000).round(2)
|
|
154
|
+
|
|
155
|
+
if memories.empty?
|
|
156
|
+
puts "[•] No memories found (#{duration}ms)"
|
|
157
|
+
return
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
puts "[✓] Found #{memories.length} memories (#{duration}ms)\n"
|
|
161
|
+
|
|
162
|
+
memories.each_with_index do |memory, index|
|
|
163
|
+
puts
|
|
164
|
+
puts "#{index + 1}. Node #{memory['id']} (#{memory['source']})"
|
|
165
|
+
puts " Created: #{memory['created_at']}"
|
|
166
|
+
puts " Content: #{memory['content']}"
|
|
167
|
+
|
|
168
|
+
# Show tags if any
|
|
169
|
+
node = HTM::Models::Node.includes(:tags).find(memory['id'])
|
|
170
|
+
if node.tags.any?
|
|
171
|
+
puts " Tags: #{node.tags.map(&:name).join(', ')}"
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def handle_stats
|
|
177
|
+
puts "\nMemory Statistics:"
|
|
178
|
+
puts
|
|
179
|
+
|
|
180
|
+
total_nodes = HTM::Models::Node.count
|
|
181
|
+
nodes_with_embeddings = HTM::Models::Node.where.not(embedding: nil).count
|
|
182
|
+
nodes_with_tags = HTM::Models::Node.joins(:tags).distinct.count
|
|
183
|
+
total_tags = HTM::Models::Tag.count
|
|
184
|
+
total_robots = HTM::Models::Robot.count
|
|
185
|
+
|
|
186
|
+
puts "Nodes:"
|
|
187
|
+
puts " Total: #{total_nodes}"
|
|
188
|
+
puts " With embeddings: #{nodes_with_embeddings} (#{percentage(nodes_with_embeddings, total_nodes)})"
|
|
189
|
+
puts " With tags: #{nodes_with_tags} (#{percentage(nodes_with_tags, total_nodes)})"
|
|
190
|
+
puts
|
|
191
|
+
|
|
192
|
+
puts "Tags:"
|
|
193
|
+
puts " Total: #{total_tags}"
|
|
194
|
+
if total_tags > 0
|
|
195
|
+
puts " Average per node: #{(total_tags.to_f / total_nodes).round(2)}"
|
|
196
|
+
end
|
|
197
|
+
puts
|
|
198
|
+
|
|
199
|
+
puts "Robots:"
|
|
200
|
+
puts " Total: #{total_robots}"
|
|
201
|
+
puts
|
|
202
|
+
|
|
203
|
+
puts "Current Robot (#{@htm.robot_name}):"
|
|
204
|
+
robot_nodes = HTM::Models::Node.where(robot_id: @htm.robot_id).count
|
|
205
|
+
puts " Nodes: #{robot_nodes}"
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def handle_help
|
|
209
|
+
puts
|
|
210
|
+
puts "HTM CLI Commands:"
|
|
211
|
+
puts
|
|
212
|
+
puts " remember <text>"
|
|
213
|
+
puts " Store information in long-term memory"
|
|
214
|
+
puts " Embeddings and tags are generated synchronously"
|
|
215
|
+
puts " Example: remember PostgreSQL is great for time-series data"
|
|
216
|
+
puts
|
|
217
|
+
puts " recall <topic>"
|
|
218
|
+
puts " Search for relevant memories using hybrid search"
|
|
219
|
+
puts " Combines vector similarity and full-text search"
|
|
220
|
+
puts " Example: recall PostgreSQL"
|
|
221
|
+
puts
|
|
222
|
+
puts " stats"
|
|
223
|
+
puts " Show memory statistics and current state"
|
|
224
|
+
puts
|
|
225
|
+
puts " help"
|
|
226
|
+
puts " Show this help message"
|
|
227
|
+
puts
|
|
228
|
+
puts " exit"
|
|
229
|
+
puts " Quit the CLI"
|
|
230
|
+
puts
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def percentage(part, total)
|
|
234
|
+
return "0%" if total.zero?
|
|
235
|
+
"#{((part.to_f / total) * 100).round(1)}%"
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Check database configuration
|
|
240
|
+
unless ENV['HTM_DBURL']
|
|
241
|
+
puts
|
|
242
|
+
puts "[✗] Error: HTM_DBURL environment variable not set"
|
|
243
|
+
puts
|
|
244
|
+
puts "Please set your database connection URL:"
|
|
245
|
+
puts " export HTM_DBURL='postgresql://user:pass@host:port/dbname'"
|
|
246
|
+
puts
|
|
247
|
+
puts "Or source your environment configuration:"
|
|
248
|
+
puts " source ~/.bashrc__tiger"
|
|
249
|
+
puts
|
|
250
|
+
exit 1
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Check Ollama connection (optional but recommended)
|
|
254
|
+
begin
|
|
255
|
+
require 'net/http'
|
|
256
|
+
uri = URI(ENV['OLLAMA_URL'] || 'http://localhost:11434')
|
|
257
|
+
response = Net::HTTP.get_response(uri)
|
|
258
|
+
rescue StandardError => e
|
|
259
|
+
puts
|
|
260
|
+
puts "[⚠] Warning: Cannot connect to Ollama (#{e.message})"
|
|
261
|
+
puts " Embeddings and tags will not be generated"
|
|
262
|
+
puts " Install Ollama: https://ollama.ai"
|
|
263
|
+
puts
|
|
264
|
+
puts "Continue anyway? (y/n) "
|
|
265
|
+
answer = gets.chomp.downcase
|
|
266
|
+
exit unless answer == 'y' || answer == 'yes'
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# Run CLI
|
|
270
|
+
HTMCli.new.run
|