htm 0.0.1 → 0.0.2
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/.envrc +1 -0
- data/.tbls.yml +30 -0
- data/CHANGELOG.md +30 -0
- data/SETUP.md +132 -101
- data/db/migrate/20250125000001_add_content_hash_to_nodes.rb +14 -0
- data/db/migrate/20250125000002_create_robot_nodes.rb +35 -0
- data/db/migrate/20250125000003_remove_source_and_robot_id_from_nodes.rb +28 -0
- data/db/migrate/20250126000001_create_working_memories.rb +19 -0
- data/db/migrate/20250126000002_remove_unused_columns.rb +12 -0
- data/db/schema.sql +226 -43
- data/docs/api/database.md +20 -232
- data/docs/api/embedding-service.md +1 -7
- data/docs/api/htm.md +195 -449
- data/docs/api/index.md +1 -7
- data/docs/api/long-term-memory.md +342 -590
- data/docs/architecture/adrs/001-postgresql-timescaledb.md +1 -1
- data/docs/architecture/adrs/003-ollama-embeddings.md +1 -1
- data/docs/architecture/adrs/010-redis-working-memory-rejected.md +2 -27
- data/docs/architecture/adrs/index.md +2 -13
- data/docs/architecture/hive-mind.md +165 -166
- data/docs/architecture/index.md +2 -2
- data/docs/architecture/overview.md +5 -171
- data/docs/architecture/two-tier-memory.md +1 -35
- data/docs/assets/images/adr-010-current-architecture.svg +37 -0
- data/docs/assets/images/adr-010-proposed-architecture.svg +48 -0
- data/docs/assets/images/adr-dependency-tree.svg +93 -0
- data/docs/assets/images/class-hierarchy.svg +55 -0
- data/docs/assets/images/exception-hierarchy.svg +45 -0
- data/docs/assets/images/htm-architecture-overview.svg +83 -0
- data/docs/assets/images/htm-complete-memory-flow.svg +160 -0
- data/docs/assets/images/htm-context-assembly-flow.svg +148 -0
- data/docs/assets/images/htm-eviction-process.svg +141 -0
- data/docs/assets/images/htm-memory-addition-flow.svg +138 -0
- data/docs/assets/images/htm-memory-recall-flow.svg +152 -0
- data/docs/assets/images/htm-node-states.svg +123 -0
- data/docs/assets/images/project-structure.svg +78 -0
- data/docs/assets/images/test-directory-structure.svg +38 -0
- data/{dbdoc → docs/database}/README.md +5 -3
- data/{dbdoc → docs/database}/public.node_tags.md +4 -5
- data/docs/database/public.node_tags.svg +106 -0
- data/{dbdoc → docs/database}/public.nodes.md +3 -8
- data/docs/database/public.nodes.svg +152 -0
- data/docs/database/public.robot_nodes.md +44 -0
- data/docs/database/public.robot_nodes.svg +121 -0
- data/{dbdoc → docs/database}/public.robots.md +1 -2
- data/docs/database/public.robots.svg +106 -0
- data/docs/database/public.working_memories.md +40 -0
- data/docs/database/public.working_memories.svg +112 -0
- data/{dbdoc → docs/database}/schema.json +342 -110
- data/docs/database/schema.svg +223 -0
- data/docs/development/index.md +1 -29
- data/docs/development/schema.md +84 -324
- data/docs/development/testing.md +1 -9
- data/docs/getting-started/index.md +47 -0
- data/docs/{installation.md → getting-started/installation.md} +2 -2
- data/docs/{quick-start.md → getting-started/quick-start.md} +5 -5
- data/docs/guides/adding-memories.md +221 -655
- data/docs/guides/search-strategies.md +85 -51
- data/docs/images/htm-er-diagram.svg +156 -0
- data/docs/index.md +16 -31
- data/docs/multi_framework_support.md +4 -4
- data/examples/basic_usage.rb +18 -16
- data/examples/cli_app/htm_cli.rb +86 -8
- data/examples/custom_llm_configuration.rb +1 -2
- data/examples/example_app/app.rb +11 -14
- data/examples/sinatra_app/Gemfile +1 -0
- data/examples/sinatra_app/Gemfile.lock +166 -0
- data/examples/sinatra_app/app.rb +219 -24
- data/lib/htm/active_record_config.rb +10 -3
- data/lib/htm/configuration.rb +265 -78
- data/lib/htm/{sinatra.rb → integrations/sinatra.rb} +87 -12
- data/lib/htm/job_adapter.rb +10 -3
- data/lib/htm/long_term_memory.rb +220 -57
- data/lib/htm/models/node.rb +36 -7
- data/lib/htm/models/robot.rb +30 -4
- data/lib/htm/models/robot_node.rb +50 -0
- data/lib/htm/models/tag.rb +52 -0
- data/lib/htm/models/working_memory_entry.rb +88 -0
- data/lib/htm/tasks.rb +4 -0
- data/lib/htm/version.rb +1 -1
- data/lib/htm.rb +34 -13
- data/lib/tasks/htm.rake +32 -1
- data/lib/tasks/jobs.rake +7 -3
- data/lib/tasks/tags.rake +34 -0
- data/mkdocs.yml +56 -9
- metadata +61 -31
- data/dbdoc/public.node_tags.svg +0 -112
- data/dbdoc/public.nodes.svg +0 -118
- data/dbdoc/public.robots.svg +0 -90
- data/dbdoc/schema.svg +0 -154
- /data/{dbdoc → docs/database}/public.node_stats.md +0 -0
- /data/{dbdoc → docs/database}/public.node_stats.svg +0 -0
- /data/{dbdoc → docs/database}/public.nodes_tags.md +0 -0
- /data/{dbdoc → docs/database}/public.nodes_tags.svg +0 -0
- /data/{dbdoc → docs/database}/public.ontology_structure.md +0 -0
- /data/{dbdoc → docs/database}/public.ontology_structure.svg +0 -0
- /data/{dbdoc → docs/database}/public.operations_log.md +0 -0
- /data/{dbdoc → docs/database}/public.operations_log.svg +0 -0
- /data/{dbdoc → docs/database}/public.relationships.md +0 -0
- /data/{dbdoc → docs/database}/public.relationships.svg +0 -0
- /data/{dbdoc → docs/database}/public.robot_activity.md +0 -0
- /data/{dbdoc → docs/database}/public.robot_activity.svg +0 -0
- /data/{dbdoc → docs/database}/public.schema_migrations.md +0 -0
- /data/{dbdoc → docs/database}/public.schema_migrations.svg +0 -0
- /data/{dbdoc → docs/database}/public.tags.md +0 -0
- /data/{dbdoc → docs/database}/public.tags.svg +0 -0
- /data/{dbdoc → docs/database}/public.topic_relationships.md +0 -0
- /data/{dbdoc → docs/database}/public.topic_relationships.svg +0 -0
data/docs/development/schema.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Database Schema Documentation
|
|
2
2
|
|
|
3
|
-
This document provides a comprehensive reference for HTM's PostgreSQL database schema, including
|
|
3
|
+
This document provides a comprehensive reference for HTM's PostgreSQL database schema, including query patterns, optimization strategies, and best practices.
|
|
4
4
|
|
|
5
5
|
## Schema Overview
|
|
6
6
|
|
|
@@ -22,367 +22,116 @@ CREATE EXTENSION IF NOT EXISTS vector WITH SCHEMA public;
|
|
|
22
22
|
|
|
23
23
|
## Entity-Relationship Diagram
|
|
24
24
|
|
|
25
|
-
Here's the complete database structure:
|
|
25
|
+
Here's the complete database structure (auto-generated by tbls):
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 900" style="background: transparent;">
|
|
29
|
-
<defs>
|
|
30
|
-
<style>
|
|
31
|
-
.table-box { fill: #1e1e1e; stroke: #4a9eff; stroke-width: 2; }
|
|
32
|
-
.table-header { fill: #2d5a8e; }
|
|
33
|
-
.text-header { fill: #ffffff; font-family: monospace; font-size: 14px; font-weight: bold; }
|
|
34
|
-
.text-field { fill: #d4d4d4; font-family: monospace; font-size: 11px; }
|
|
35
|
-
.text-type { fill: #8cb4e8; font-family: monospace; font-size: 10px; }
|
|
36
|
-
.relation-line { stroke: #4a9eff; stroke-width: 1.5; fill: none; }
|
|
37
|
-
.arrow { fill: #4a9eff; }
|
|
38
|
-
.join-table { fill: #1e3a1e; stroke: #4a9eff; stroke-width: 2; }
|
|
39
|
-
</style>
|
|
40
|
-
</defs>
|
|
27
|
+

|
|
41
28
|
|
|
42
|
-
|
|
43
|
-
<rect class="table-box" x="50" y="50" width="280" height="140" rx="5"/>
|
|
44
|
-
<rect class="table-header" x="50" y="50" width="280" height="35" rx="5"/>
|
|
45
|
-
<text class="text-header" x="190" y="73" text-anchor="middle">robots</text>
|
|
29
|
+
## Table Reference
|
|
46
30
|
|
|
47
|
-
|
|
48
|
-
<text class="text-type" x="320" y="100" text-anchor="end">BIGSERIAL PK</text>
|
|
31
|
+
For detailed table definitions, columns, indexes, and constraints, see the auto-generated documentation:
|
|
49
32
|
|
|
50
|
-
|
|
51
|
-
<text class="text-type" x="320" y="120" text-anchor="end">TEXT</text>
|
|
33
|
+
### Core Tables
|
|
52
34
|
|
|
53
|
-
|
|
54
|
-
|
|
35
|
+
| Table | Description | Details |
|
|
36
|
+
|-------|-------------|---------|
|
|
37
|
+
| [robots](../database/public.robots.md) | Registry of all LLM robots using the HTM system | Stores robot metadata and activity tracking |
|
|
38
|
+
| [nodes](../database/public.nodes.md) | Core memory storage for conversation messages and context | Vector embeddings, full-text search, deduplication |
|
|
39
|
+
| [tags](../database/public.tags.md) | Unique hierarchical tag names for categorization | Colon-separated namespaces (e.g., `ai:llm:embeddings`) |
|
|
40
|
+
| [working_memories](../database/public.working_memories.md) | Per-robot working memory state | Optional persistence for token-limited context |
|
|
55
41
|
|
|
56
|
-
|
|
57
|
-
<text class="text-type" x="320" y="160" text-anchor="end">TIMESTAMPTZ</text>
|
|
42
|
+
### Join Tables
|
|
58
43
|
|
|
59
|
-
|
|
60
|
-
|
|
44
|
+
| Table | Description | Details |
|
|
45
|
+
|-------|-------------|---------|
|
|
46
|
+
| [robot_nodes](../database/public.robot_nodes.md) | Links robots to nodes (many-to-many) | Enables "hive mind" shared memory architecture |
|
|
47
|
+
| [node_tags](../database/public.node_tags.md) | Links nodes to tags (many-to-many) | Flexible multi-tag categorization |
|
|
61
48
|
|
|
62
|
-
|
|
63
|
-
<rect class="table-box" x="50" y="250" width="280" height="400" rx="5"/>
|
|
64
|
-
<rect class="table-header" x="50" y="250" width="280" height="35" rx="5"/>
|
|
65
|
-
<text class="text-header" x="190" y="273" text-anchor="middle">nodes</text>
|
|
49
|
+
### System Tables
|
|
66
50
|
|
|
67
|
-
|
|
68
|
-
|
|
51
|
+
| Table | Description | Details |
|
|
52
|
+
|-------|-------------|---------|
|
|
53
|
+
| [schema_migrations](../database/public.schema_migrations.md) | ActiveRecord migration tracking | Tracks applied migrations |
|
|
69
54
|
|
|
70
|
-
|
|
71
|
-
<text class="text-type" x="320" y="320" text-anchor="end">TEXT NOT NULL</text>
|
|
55
|
+
For the complete schema overview including all stored procedures and functions, see the [Database Tables Overview](../database/README.md).
|
|
72
56
|
|
|
73
|
-
|
|
74
|
-
<text class="text-type" x="320" y="340" text-anchor="end">TEXT NOT NULL</text>
|
|
57
|
+
## Key Concepts
|
|
75
58
|
|
|
76
|
-
|
|
77
|
-
<text class="text-type" x="320" y="360" text-anchor="end">TEXT</text>
|
|
59
|
+
### Content Deduplication
|
|
78
60
|
|
|
79
|
-
|
|
80
|
-
<text class="text-type" x="320" y="380" text-anchor="end">TEXT</text>
|
|
61
|
+
Content deduplication is enforced via SHA-256 hashing in the `nodes` table:
|
|
81
62
|
|
|
82
|
-
|
|
83
|
-
|
|
63
|
+
1. When `remember()` is called, a SHA-256 hash of the content is computed
|
|
64
|
+
2. If a node with the same `content_hash` exists, the existing node is reused
|
|
65
|
+
3. A new `robot_nodes` association is created (or updated if it already exists)
|
|
66
|
+
4. This ensures identical memories are stored once but can be "remembered" by multiple robots
|
|
84
67
|
|
|
85
|
-
|
|
86
|
-
<text class="text-type" x="320" y="420" text-anchor="end">TIMESTAMPTZ</text>
|
|
68
|
+
### Hierarchical Tags
|
|
87
69
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
<text class="text-type" x="320" y="460" text-anchor="end">TIMESTAMPTZ</text>
|
|
93
|
-
|
|
94
|
-
<text class="text-field" x="60" y="480">token_count</text>
|
|
95
|
-
<text class="text-type" x="320" y="480" text-anchor="end">INTEGER</text>
|
|
96
|
-
|
|
97
|
-
<text class="text-field" x="60" y="500">in_working_memory</text>
|
|
98
|
-
<text class="text-type" x="320" y="500" text-anchor="end">BOOLEAN</text>
|
|
99
|
-
|
|
100
|
-
<text class="text-field" x="60" y="520">robot_id</text>
|
|
101
|
-
<text class="text-type" x="320" y="520" text-anchor="end">BIGINT FK</text>
|
|
102
|
-
|
|
103
|
-
<text class="text-field" x="60" y="540">embedding</text>
|
|
104
|
-
<text class="text-type" x="320" y="540" text-anchor="end">vector(2000)</text>
|
|
105
|
-
|
|
106
|
-
<text class="text-field" x="60" y="560">embedding_dimension</text>
|
|
107
|
-
<text class="text-type" x="320" y="560" text-anchor="end">INTEGER</text>
|
|
108
|
-
|
|
109
|
-
<!-- Tags Table -->
|
|
110
|
-
<rect class="table-box" x="850" y="250" width="280" height="120" rx="5"/>
|
|
111
|
-
<rect class="table-header" x="850" y="250" width="280" height="35" rx="5"/>
|
|
112
|
-
<text class="text-header" x="990" y="273" text-anchor="middle">tags</text>
|
|
113
|
-
|
|
114
|
-
<text class="text-field" x="860" y="300">id</text>
|
|
115
|
-
<text class="text-type" x="1120" y="300" text-anchor="end">BIGSERIAL PK</text>
|
|
116
|
-
|
|
117
|
-
<text class="text-field" x="860" y="320">name</text>
|
|
118
|
-
<text class="text-type" x="1120" y="320" text-anchor="end">TEXT UNIQUE</text>
|
|
119
|
-
|
|
120
|
-
<text class="text-field" x="860" y="340">created_at</text>
|
|
121
|
-
<text class="text-type" x="1120" y="340" text-anchor="end">TIMESTAMPTZ</text>
|
|
122
|
-
|
|
123
|
-
<!-- nodes_tags Join Table -->
|
|
124
|
-
<rect class="join-table" x="450" y="420" width="280" height="140" rx="5"/>
|
|
125
|
-
<rect class="table-header" x="450" y="420" width="280" height="35" rx="5"/>
|
|
126
|
-
<text class="text-header" x="590" y="443" text-anchor="middle">nodes_tags</text>
|
|
127
|
-
|
|
128
|
-
<text class="text-field" x="460" y="470">id</text>
|
|
129
|
-
<text class="text-type" x="720" y="470" text-anchor="end">BIGSERIAL PK</text>
|
|
130
|
-
|
|
131
|
-
<text class="text-field" x="460" y="490">node_id</text>
|
|
132
|
-
<text class="text-type" x="720" y="490" text-anchor="end">BIGINT FK</text>
|
|
133
|
-
|
|
134
|
-
<text class="text-field" x="460" y="510">tag_id</text>
|
|
135
|
-
<text class="text-type" x="720" y="510" text-anchor="end">BIGINT FK</text>
|
|
136
|
-
|
|
137
|
-
<text class="text-field" x="460" y="530">created_at</text>
|
|
138
|
-
<text class="text-type" x="720" y="530" text-anchor="end">TIMESTAMPTZ</text>
|
|
139
|
-
|
|
140
|
-
<!-- Relationships: robots -> nodes -->
|
|
141
|
-
<path class="relation-line" d="M 190 190 L 190 250"/>
|
|
142
|
-
<polygon class="arrow" points="190,250 185,240 195,240"/>
|
|
143
|
-
|
|
144
|
-
<!-- Relationships: nodes -> nodes_tags -->
|
|
145
|
-
<path class="relation-line" d="M 330 490 L 450 490"/>
|
|
146
|
-
<polygon class="arrow" points="450,490 440,485 440,495"/>
|
|
147
|
-
|
|
148
|
-
<!-- Relationships: tags -> nodes_tags -->
|
|
149
|
-
<path class="relation-line" d="M 850 310 L 730 310 L 730 510 L 730 510"/>
|
|
150
|
-
<polygon class="arrow" points="730,510 725,500 735,500"/>
|
|
151
|
-
|
|
152
|
-
<!-- Legend -->
|
|
153
|
-
<text class="text-field" x="50" y="720" font-weight="bold">Legend:</text>
|
|
154
|
-
<text class="text-field" x="50" y="740">PK = Primary Key</text>
|
|
155
|
-
<text class="text-field" x="200" y="740">FK = Foreign Key</text>
|
|
156
|
-
<text class="text-field" x="50" y="760">Green box = Join table (many-to-many)</text>
|
|
157
|
-
|
|
158
|
-
<!-- Annotations -->
|
|
159
|
-
<text class="text-field" x="400" y="370" font-style="italic">1:N</text>
|
|
160
|
-
<text class="text-field" x="380" y="480" font-style="italic">N:M</text>
|
|
161
|
-
<text class="text-field" x="770" y="480" font-style="italic">N:M</text>
|
|
162
|
-
</svg>
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
## Table Definitions
|
|
166
|
-
|
|
167
|
-
### robots
|
|
168
|
-
|
|
169
|
-
The robots table stores registration and metadata for all LLM agents using the HTM system.
|
|
170
|
-
|
|
171
|
-
**Purpose**: Registry of all robots (LLM agents) with their configuration and activity tracking.
|
|
70
|
+
Tags use colon-separated hierarchies for organization:
|
|
71
|
+
- `programming:ruby:gems` - Programming > Ruby > Gems
|
|
72
|
+
- `database:postgresql:extensions` - Database > PostgreSQL > Extensions
|
|
73
|
+
- `ai:llm:embeddings` - AI > LLM > Embeddings
|
|
172
74
|
|
|
75
|
+
Query by prefix to find all related tags:
|
|
173
76
|
```sql
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
name text,
|
|
177
|
-
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
|
|
178
|
-
last_active timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
|
|
179
|
-
metadata jsonb
|
|
180
|
-
);
|
|
181
|
-
|
|
182
|
-
ALTER TABLE ONLY public.robots ALTER COLUMN id SET DEFAULT nextval('public.robots_id_seq'::regclass);
|
|
183
|
-
ALTER TABLE ONLY public.robots ADD CONSTRAINT robots_pkey PRIMARY KEY (id);
|
|
77
|
+
SELECT * FROM tags WHERE name LIKE 'database:%'; -- All database-related tags
|
|
78
|
+
SELECT * FROM tags WHERE name LIKE 'ai:llm:%'; -- All LLM-related tags
|
|
184
79
|
```
|
|
185
80
|
|
|
186
|
-
|
|
81
|
+
### Remember Tracking
|
|
187
82
|
|
|
188
|
-
|
|
189
|
-
|--------|------|----------|---------|-------------|
|
|
190
|
-
| `id` | BIGINT | NO | AUTO | Unique identifier (primary key) |
|
|
191
|
-
| `name` | TEXT | YES | NULL | Human-readable name for the robot |
|
|
192
|
-
| `created_at` | TIMESTAMPTZ | YES | NOW() | When the robot was first registered |
|
|
193
|
-
| `last_active` | TIMESTAMPTZ | YES | NOW() | Last time the robot accessed the system |
|
|
194
|
-
| `metadata` | JSONB | YES | NULL | Robot-specific configuration and metadata |
|
|
83
|
+
The `robot_nodes` table tracks per-robot remember metadata:
|
|
195
84
|
|
|
196
|
-
|
|
197
|
-
|
|
85
|
+
1. `first_remembered_at` - When this robot first encountered this content
|
|
86
|
+
2. `last_remembered_at` - Updated each time the robot tries to remember the same content
|
|
87
|
+
3. `remember_count` - Incremented each time (useful for identifying frequently reinforced memories)
|
|
198
88
|
|
|
199
|
-
|
|
200
|
-
-
|
|
89
|
+
This allows querying for:
|
|
90
|
+
- Recently reinforced memories: `ORDER BY last_remembered_at DESC`
|
|
91
|
+
- Frequently remembered content: `ORDER BY remember_count DESC`
|
|
92
|
+
- New vs old memories: Compare `first_remembered_at` across robots
|
|
201
93
|
|
|
202
94
|
---
|
|
203
95
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
The core table storing all memory nodes with vector embeddings for semantic search.
|
|
207
|
-
|
|
208
|
-
**Purpose**: Stores all memories (conversation messages, facts, decisions, code, etc.) with full-text and vector search capabilities.
|
|
209
|
-
|
|
210
|
-
```sql
|
|
211
|
-
CREATE TABLE public.nodes (
|
|
212
|
-
id bigint NOT NULL,
|
|
213
|
-
content text NOT NULL,
|
|
214
|
-
speaker text NOT NULL,
|
|
215
|
-
type text,
|
|
216
|
-
category text,
|
|
217
|
-
importance double precision DEFAULT 1.0,
|
|
218
|
-
created_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
|
|
219
|
-
updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
|
|
220
|
-
last_accessed timestamp with time zone DEFAULT CURRENT_TIMESTAMP,
|
|
221
|
-
token_count integer,
|
|
222
|
-
in_working_memory boolean DEFAULT false,
|
|
223
|
-
robot_id bigint NOT NULL,
|
|
224
|
-
embedding public.vector(2000),
|
|
225
|
-
embedding_dimension integer,
|
|
226
|
-
CONSTRAINT check_embedding_dimension CHECK (((embedding_dimension IS NULL) OR ((embedding_dimension > 0) AND (embedding_dimension <= 2000))))
|
|
227
|
-
);
|
|
228
|
-
|
|
229
|
-
ALTER TABLE ONLY public.nodes ALTER COLUMN id SET DEFAULT nextval('public.nodes_id_seq'::regclass);
|
|
230
|
-
ALTER TABLE ONLY public.nodes ADD CONSTRAINT nodes_pkey PRIMARY KEY (id);
|
|
231
|
-
ALTER TABLE ONLY public.nodes
|
|
232
|
-
ADD CONSTRAINT fk_rails_60162e9d3a FOREIGN KEY (robot_id) REFERENCES public.robots(id) ON DELETE CASCADE;
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
**Columns**:
|
|
236
|
-
|
|
237
|
-
| Column | Type | Nullable | Default | Description |
|
|
238
|
-
|--------|------|----------|---------|-------------|
|
|
239
|
-
| `id` | BIGINT | NO | AUTO | Unique identifier (primary key) |
|
|
240
|
-
| `content` | TEXT | NO | - | The conversation message/utterance content |
|
|
241
|
-
| `speaker` | TEXT | NO | - | Who said it: user or robot name |
|
|
242
|
-
| `type` | TEXT | YES | NULL | Memory type: fact, context, code, preference, decision, question |
|
|
243
|
-
| `category` | TEXT | YES | NULL | Optional category for organizing memories |
|
|
244
|
-
| `importance` | DOUBLE PRECISION | YES | 1.0 | Importance score (0.0-1.0) for prioritizing recall |
|
|
245
|
-
| `created_at` | TIMESTAMPTZ | YES | NOW() | When this memory was created |
|
|
246
|
-
| `updated_at` | TIMESTAMPTZ | YES | NOW() | When this memory was last modified |
|
|
247
|
-
| `last_accessed` | TIMESTAMPTZ | YES | NOW() | When this memory was last accessed |
|
|
248
|
-
| `token_count` | INTEGER | YES | NULL | Number of tokens in the content (for context budget management) |
|
|
249
|
-
| `in_working_memory` | BOOLEAN | YES | FALSE | Whether this memory is currently in working memory |
|
|
250
|
-
| `robot_id` | BIGINT | NO | - | ID of the robot that owns this memory |
|
|
251
|
-
| `embedding` | vector(2000) | YES | NULL | Vector embedding (max 2000 dimensions) for semantic search |
|
|
252
|
-
| `embedding_dimension` | INTEGER | YES | NULL | Actual number of dimensions used in the embedding vector (max 2000) |
|
|
253
|
-
|
|
254
|
-
**Indexes**:
|
|
255
|
-
|
|
256
|
-
- `PRIMARY KEY` on `id`
|
|
257
|
-
- `idx_nodes_robot_id` BTREE on `robot_id`
|
|
258
|
-
- `idx_nodes_speaker` BTREE on `speaker`
|
|
259
|
-
- `idx_nodes_type` BTREE on `type`
|
|
260
|
-
- `idx_nodes_category` BTREE on `category`
|
|
261
|
-
- `idx_nodes_created_at` BTREE on `created_at`
|
|
262
|
-
- `idx_nodes_updated_at` BTREE on `updated_at`
|
|
263
|
-
- `idx_nodes_last_accessed` BTREE on `last_accessed`
|
|
264
|
-
- `idx_nodes_in_working_memory` BTREE on `in_working_memory`
|
|
265
|
-
- `idx_nodes_embedding` HNSW on `embedding` using `vector_cosine_ops` (m=16, ef_construction=64)
|
|
266
|
-
- `idx_nodes_content_gin` GIN on `to_tsvector('english', content)` for full-text search
|
|
267
|
-
- `idx_nodes_content_trgm` GIN on `content` using `gin_trgm_ops` for fuzzy matching
|
|
268
|
-
|
|
269
|
-
**Foreign Keys**:
|
|
270
|
-
- `robot_id` references `robots(id)` ON DELETE CASCADE
|
|
271
|
-
|
|
272
|
-
**Relationships**:
|
|
273
|
-
- Many nodes belong to one robot (N:1)
|
|
274
|
-
- Many nodes have many tags through nodes_tags (N:M)
|
|
275
|
-
|
|
276
|
-
**Check Constraints**:
|
|
277
|
-
- `check_embedding_dimension`: Ensures embedding_dimension is NULL or between 1 and 2000
|
|
278
|
-
|
|
279
|
-
---
|
|
280
|
-
|
|
281
|
-
### tags
|
|
282
|
-
|
|
283
|
-
The tags table stores unique hierarchical tag names for categorization.
|
|
96
|
+
## Common Query Patterns
|
|
284
97
|
|
|
285
|
-
|
|
98
|
+
### Finding Nodes for a Robot
|
|
286
99
|
|
|
287
100
|
```sql
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
ALTER TABLE ONLY public.tags ALTER COLUMN id SET DEFAULT nextval('public.tags_id_seq'::regclass);
|
|
295
|
-
ALTER TABLE ONLY public.tags ADD CONSTRAINT tags_pkey PRIMARY KEY (id);
|
|
101
|
+
SELECT n.*
|
|
102
|
+
FROM nodes n
|
|
103
|
+
JOIN robot_nodes rn ON n.id = rn.node_id
|
|
104
|
+
WHERE rn.robot_id = $1
|
|
105
|
+
ORDER BY rn.last_remembered_at DESC;
|
|
296
106
|
```
|
|
297
107
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
| Column | Type | Nullable | Default | Description |
|
|
301
|
-
|--------|------|----------|---------|-------------|
|
|
302
|
-
| `id` | BIGINT | NO | AUTO | Unique identifier (primary key) |
|
|
303
|
-
| `name` | TEXT | NO | - | Hierarchical tag in format: root:level1:level2 (e.g., database:postgresql:timescaledb) |
|
|
304
|
-
| `created_at` | TIMESTAMPTZ | YES | NOW() | When this tag was created |
|
|
305
|
-
|
|
306
|
-
**Indexes**:
|
|
307
|
-
- `PRIMARY KEY` on `id`
|
|
308
|
-
- `idx_tags_name_unique` UNIQUE BTREE on `name`
|
|
309
|
-
- `idx_tags_name_pattern` BTREE on `name` with `text_pattern_ops` for pattern matching
|
|
310
|
-
|
|
311
|
-
**Relationships**:
|
|
312
|
-
- Many tags belong to many nodes through nodes_tags (N:M)
|
|
313
|
-
|
|
314
|
-
**Tag Hierarchy**:
|
|
108
|
+
### Finding Robots that Share a Node
|
|
315
109
|
|
|
316
|
-
Tags use colon-separated hierarchies for organization:
|
|
317
|
-
- `programming:ruby:gems` - Programming > Ruby > Gems
|
|
318
|
-
- `database:postgresql:extensions` - Database > PostgreSQL > Extensions
|
|
319
|
-
- `ai:llm:embeddings` - AI > LLM > Embeddings
|
|
320
|
-
|
|
321
|
-
This allows querying by prefix to find all related tags:
|
|
322
110
|
```sql
|
|
323
|
-
SELECT
|
|
324
|
-
|
|
111
|
+
SELECT r.*
|
|
112
|
+
FROM robots r
|
|
113
|
+
JOIN robot_nodes rn ON r.id = rn.robot_id
|
|
114
|
+
WHERE rn.node_id = $1
|
|
115
|
+
ORDER BY rn.first_remembered_at;
|
|
325
116
|
```
|
|
326
117
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
### nodes_tags
|
|
330
|
-
|
|
331
|
-
The nodes_tags join table implements the many-to-many relationship between nodes and tags.
|
|
332
|
-
|
|
333
|
-
**Purpose**: Links nodes to tags, allowing each node to have multiple tags and each tag to be applied to multiple nodes.
|
|
118
|
+
### Finding Frequently Remembered Content
|
|
334
119
|
|
|
335
120
|
```sql
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
ALTER TABLE ONLY public.nodes_tags ALTER COLUMN id SET DEFAULT nextval('public.node_tags_id_seq'::regclass);
|
|
344
|
-
ALTER TABLE ONLY public.nodes_tags ADD CONSTRAINT node_tags_pkey PRIMARY KEY (id);
|
|
345
|
-
|
|
346
|
-
ALTER TABLE ONLY public.nodes_tags
|
|
347
|
-
ADD CONSTRAINT fk_rails_b0b726ecf8 FOREIGN KEY (node_id) REFERENCES public.nodes(id) ON DELETE CASCADE;
|
|
348
|
-
ALTER TABLE ONLY public.nodes_tags
|
|
349
|
-
ADD CONSTRAINT fk_rails_eccc99cec5 FOREIGN KEY (tag_id) REFERENCES public.tags(id) ON DELETE CASCADE;
|
|
121
|
+
SELECT n.*, rn.remember_count, rn.first_remembered_at, rn.last_remembered_at
|
|
122
|
+
FROM nodes n
|
|
123
|
+
JOIN robot_nodes rn ON n.id = rn.node_id
|
|
124
|
+
WHERE rn.robot_id = $1
|
|
125
|
+
ORDER BY rn.remember_count DESC
|
|
126
|
+
LIMIT 10;
|
|
350
127
|
```
|
|
351
128
|
|
|
352
|
-
**Columns**:
|
|
353
|
-
|
|
354
|
-
| Column | Type | Nullable | Default | Description |
|
|
355
|
-
|--------|------|----------|---------|-------------|
|
|
356
|
-
| `id` | BIGINT | NO | AUTO | Unique identifier (primary key) |
|
|
357
|
-
| `node_id` | BIGINT | NO | - | ID of the node being tagged |
|
|
358
|
-
| `tag_id` | BIGINT | NO | - | ID of the tag being applied |
|
|
359
|
-
| `created_at` | TIMESTAMPTZ | YES | NOW() | When this association was created |
|
|
360
|
-
|
|
361
|
-
**Indexes**:
|
|
362
|
-
- `PRIMARY KEY` on `id`
|
|
363
|
-
- `idx_node_tags_unique` UNIQUE BTREE on `(node_id, tag_id)` - Prevents duplicate associations
|
|
364
|
-
- `idx_node_tags_node_id` BTREE on `node_id` - Fast lookups of tags for a node
|
|
365
|
-
- `idx_node_tags_tag_id` BTREE on `tag_id` - Fast lookups of nodes for a tag
|
|
366
|
-
|
|
367
|
-
**Foreign Keys**:
|
|
368
|
-
- `node_id` references `nodes(id)` ON DELETE CASCADE
|
|
369
|
-
- `tag_id` references `tags(id)` ON DELETE CASCADE
|
|
370
|
-
|
|
371
|
-
**Cascade Behavior**:
|
|
372
|
-
- When a node is deleted, all its tag associations are automatically removed
|
|
373
|
-
- When a tag is deleted, all associations to that tag are automatically removed
|
|
374
|
-
- The join table ensures referential integrity between nodes and tags
|
|
375
|
-
|
|
376
|
-
---
|
|
377
|
-
|
|
378
|
-
## Common Query Patterns
|
|
379
|
-
|
|
380
129
|
### Finding Tags for a Node
|
|
381
130
|
|
|
382
131
|
```sql
|
|
383
132
|
SELECT t.name
|
|
384
133
|
FROM tags t
|
|
385
|
-
JOIN
|
|
134
|
+
JOIN node_tags nt ON t.id = nt.tag_id
|
|
386
135
|
WHERE nt.node_id = $1
|
|
387
136
|
ORDER BY t.name;
|
|
388
137
|
```
|
|
@@ -392,7 +141,7 @@ ORDER BY t.name;
|
|
|
392
141
|
```sql
|
|
393
142
|
SELECT n.*
|
|
394
143
|
FROM nodes n
|
|
395
|
-
JOIN
|
|
144
|
+
JOIN node_tags nt ON n.id = nt.node_id
|
|
396
145
|
JOIN tags t ON nt.tag_id = t.id
|
|
397
146
|
WHERE t.name = 'database:postgresql'
|
|
398
147
|
ORDER BY n.created_at DESC;
|
|
@@ -403,7 +152,7 @@ ORDER BY n.created_at DESC;
|
|
|
403
152
|
```sql
|
|
404
153
|
SELECT n.*
|
|
405
154
|
FROM nodes n
|
|
406
|
-
JOIN
|
|
155
|
+
JOIN node_tags nt ON n.id = nt.node_id
|
|
407
156
|
JOIN tags t ON nt.tag_id = t.id
|
|
408
157
|
WHERE t.name LIKE 'ai:llm:%'
|
|
409
158
|
ORDER BY n.created_at DESC;
|
|
@@ -417,8 +166,8 @@ SELECT
|
|
|
417
166
|
t2.name AS topic2,
|
|
418
167
|
COUNT(DISTINCT nt1.node_id) AS shared_nodes
|
|
419
168
|
FROM tags t1
|
|
420
|
-
JOIN
|
|
421
|
-
JOIN
|
|
169
|
+
JOIN node_tags nt1 ON t1.id = nt1.tag_id
|
|
170
|
+
JOIN node_tags nt2 ON nt1.node_id = nt2.node_id
|
|
422
171
|
JOIN tags t2 ON nt2.tag_id = t2.id
|
|
423
172
|
WHERE t1.name < t2.name
|
|
424
173
|
GROUP BY t1.name, t2.name
|
|
@@ -431,7 +180,7 @@ ORDER BY shared_nodes DESC;
|
|
|
431
180
|
```sql
|
|
432
181
|
SELECT n.*, n.embedding <=> $1::vector AS distance
|
|
433
182
|
FROM nodes n
|
|
434
|
-
JOIN
|
|
183
|
+
JOIN node_tags nt ON n.id = nt.node_id
|
|
435
184
|
JOIN tags t ON nt.tag_id = t.id
|
|
436
185
|
WHERE t.name = 'programming:ruby'
|
|
437
186
|
AND n.embedding IS NOT NULL
|
|
@@ -444,7 +193,7 @@ LIMIT 10;
|
|
|
444
193
|
```sql
|
|
445
194
|
SELECT n.*, ts_rank(to_tsvector('english', n.content), query) AS rank
|
|
446
195
|
FROM nodes n
|
|
447
|
-
JOIN
|
|
196
|
+
JOIN node_tags nt ON n.id = nt.node_id
|
|
448
197
|
JOIN tags t ON nt.tag_id = t.id,
|
|
449
198
|
to_tsquery('english', 'database & optimization') query
|
|
450
199
|
WHERE to_tsvector('english', n.content) @@ query
|
|
@@ -453,6 +202,17 @@ ORDER BY rank DESC
|
|
|
453
202
|
LIMIT 20;
|
|
454
203
|
```
|
|
455
204
|
|
|
205
|
+
### Finding Content Shared by Multiple Robots
|
|
206
|
+
|
|
207
|
+
```sql
|
|
208
|
+
SELECT n.*, COUNT(DISTINCT rn.robot_id) AS robot_count
|
|
209
|
+
FROM nodes n
|
|
210
|
+
JOIN robot_nodes rn ON n.id = rn.node_id
|
|
211
|
+
GROUP BY n.id
|
|
212
|
+
HAVING COUNT(DISTINCT rn.robot_id) > 1
|
|
213
|
+
ORDER BY robot_count DESC;
|
|
214
|
+
```
|
|
215
|
+
|
|
456
216
|
---
|
|
457
217
|
|
|
458
218
|
## Database Optimization
|
data/docs/development/testing.md
CHANGED
|
@@ -147,15 +147,7 @@ ruby -r debug test/htm_test.rb
|
|
|
147
147
|
|
|
148
148
|
### Test File Layout
|
|
149
149
|
|
|
150
|
-
|
|
151
|
-
test/
|
|
152
|
-
├── test_helper.rb # Shared test configuration
|
|
153
|
-
├── htm_test.rb # Unit tests for HTM class
|
|
154
|
-
├── embedding_service_test.rb # Unit tests for EmbeddingService
|
|
155
|
-
├── integration_test.rb # Integration tests
|
|
156
|
-
└── fixtures/ # Test data (future)
|
|
157
|
-
└── sample_memories.json
|
|
158
|
-
```
|
|
150
|
+

|
|
159
151
|
|
|
160
152
|
### Test File Template
|
|
161
153
|
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
Welcome to HTM (Hierarchical Temporary Memory)! This section will help you get up and running quickly.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
HTM provides intelligent memory management for LLM-based applications (robots) with a two-tier architecture:
|
|
8
|
+
|
|
9
|
+
- **Long-term Memory**: Durable PostgreSQL storage with vector embeddings for semantic search
|
|
10
|
+
- **Working Memory**: Token-limited in-memory context for immediate LLM use
|
|
11
|
+
|
|
12
|
+
## What You'll Learn
|
|
13
|
+
|
|
14
|
+
<div class="grid cards" markdown>
|
|
15
|
+
|
|
16
|
+
- :material-download:{ .lg .middle } **Installation**
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
Set up HTM in your Ruby project with all required dependencies including PostgreSQL, pgvector, and Ollama.
|
|
21
|
+
|
|
22
|
+
[:octicons-arrow-right-24: Install HTM](installation.md)
|
|
23
|
+
|
|
24
|
+
- :material-rocket-launch:{ .lg .middle } **Quick Start**
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
Build your first memory-enabled robot in minutes with practical examples and code snippets.
|
|
29
|
+
|
|
30
|
+
[:octicons-arrow-right-24: Get started](quick-start.md)
|
|
31
|
+
|
|
32
|
+
</div>
|
|
33
|
+
|
|
34
|
+
## Prerequisites
|
|
35
|
+
|
|
36
|
+
Before installing HTM, ensure you have:
|
|
37
|
+
|
|
38
|
+
- **Ruby 3.1+** - HTM uses modern Ruby features
|
|
39
|
+
- **PostgreSQL 14+** - With pgvector and pg_trgm extensions
|
|
40
|
+
- **Ollama** (optional) - For local embedding generation
|
|
41
|
+
|
|
42
|
+
## Next Steps
|
|
43
|
+
|
|
44
|
+
1. **[Install HTM](installation.md)** - Set up the gem and database
|
|
45
|
+
2. **[Quick Start](quick-start.md)** - Create your first memory-enabled robot
|
|
46
|
+
3. **[Architecture Overview](../architecture/overview.md)** - Understand how HTM works
|
|
47
|
+
4. **[Guides](../guides/index.md)** - Deep dive into specific features
|
|
@@ -453,8 +453,8 @@ psql $HTM_DBURL -c "
|
|
|
453
453
|
Now that HTM is installed, you're ready to start building:
|
|
454
454
|
|
|
455
455
|
1. **[Quick Start Guide](quick-start.md)**: Build your first HTM application in 5 minutes
|
|
456
|
-
2. **[User Guide](guides/getting-started.md)**: Learn all HTM features in depth
|
|
457
|
-
3. **[API Reference](api/htm.md)**: Explore the complete API documentation
|
|
456
|
+
2. **[User Guide](../guides/getting-started.md)**: Learn all HTM features in depth
|
|
457
|
+
3. **[API Reference](../api/htm.md)**: Explore the complete API documentation
|
|
458
458
|
4. **[Examples](https://github.com/madbomber/htm/tree/main/examples)**: See real-world usage examples
|
|
459
459
|
|
|
460
460
|
## Getting Help
|
|
@@ -499,9 +499,9 @@ Congratulations! You've learned the basics of HTM. Here's what to explore next:
|
|
|
499
499
|
|
|
500
500
|
### Explore Advanced Features
|
|
501
501
|
|
|
502
|
-
- **[User Guide](guides/getting-started.md)**: Deep dive into all HTM features
|
|
503
|
-
- **[API Reference](api/htm.md)**: Complete API documentation
|
|
504
|
-
- **[Architecture Guide](architecture/overview.md)**: Understand HTM's internals
|
|
502
|
+
- **[User Guide](../guides/getting-started.md)**: Deep dive into all HTM features
|
|
503
|
+
- **[API Reference](../api/htm.md)**: Complete API documentation
|
|
504
|
+
- **[Architecture Guide](../architecture/overview.md)**: Understand HTM's internals
|
|
505
505
|
|
|
506
506
|
### Build Real Applications
|
|
507
507
|
|
|
@@ -648,8 +648,8 @@ memories = htm.recall(
|
|
|
648
648
|
## Additional Resources
|
|
649
649
|
|
|
650
650
|
- **[Installation Guide](installation.md)**: Complete setup instructions
|
|
651
|
-
- **[User Guide](guides/getting-started.md)**: Comprehensive feature documentation
|
|
652
|
-
- **[API Reference](api/htm.md)**: Detailed API documentation
|
|
651
|
+
- **[User Guide](../guides/getting-started.md)**: Comprehensive feature documentation
|
|
652
|
+
- **[API Reference](../api/htm.md)**: Detailed API documentation
|
|
653
653
|
- **[Examples](https://github.com/madbomber/htm/tree/main/examples)**: Real-world code examples
|
|
654
654
|
|
|
655
655
|
Happy coding with HTM! 🚀
|