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.
Files changed (109) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +1 -0
  3. data/.tbls.yml +30 -0
  4. data/CHANGELOG.md +30 -0
  5. data/SETUP.md +132 -101
  6. data/db/migrate/20250125000001_add_content_hash_to_nodes.rb +14 -0
  7. data/db/migrate/20250125000002_create_robot_nodes.rb +35 -0
  8. data/db/migrate/20250125000003_remove_source_and_robot_id_from_nodes.rb +28 -0
  9. data/db/migrate/20250126000001_create_working_memories.rb +19 -0
  10. data/db/migrate/20250126000002_remove_unused_columns.rb +12 -0
  11. data/db/schema.sql +226 -43
  12. data/docs/api/database.md +20 -232
  13. data/docs/api/embedding-service.md +1 -7
  14. data/docs/api/htm.md +195 -449
  15. data/docs/api/index.md +1 -7
  16. data/docs/api/long-term-memory.md +342 -590
  17. data/docs/architecture/adrs/001-postgresql-timescaledb.md +1 -1
  18. data/docs/architecture/adrs/003-ollama-embeddings.md +1 -1
  19. data/docs/architecture/adrs/010-redis-working-memory-rejected.md +2 -27
  20. data/docs/architecture/adrs/index.md +2 -13
  21. data/docs/architecture/hive-mind.md +165 -166
  22. data/docs/architecture/index.md +2 -2
  23. data/docs/architecture/overview.md +5 -171
  24. data/docs/architecture/two-tier-memory.md +1 -35
  25. data/docs/assets/images/adr-010-current-architecture.svg +37 -0
  26. data/docs/assets/images/adr-010-proposed-architecture.svg +48 -0
  27. data/docs/assets/images/adr-dependency-tree.svg +93 -0
  28. data/docs/assets/images/class-hierarchy.svg +55 -0
  29. data/docs/assets/images/exception-hierarchy.svg +45 -0
  30. data/docs/assets/images/htm-architecture-overview.svg +83 -0
  31. data/docs/assets/images/htm-complete-memory-flow.svg +160 -0
  32. data/docs/assets/images/htm-context-assembly-flow.svg +148 -0
  33. data/docs/assets/images/htm-eviction-process.svg +141 -0
  34. data/docs/assets/images/htm-memory-addition-flow.svg +138 -0
  35. data/docs/assets/images/htm-memory-recall-flow.svg +152 -0
  36. data/docs/assets/images/htm-node-states.svg +123 -0
  37. data/docs/assets/images/project-structure.svg +78 -0
  38. data/docs/assets/images/test-directory-structure.svg +38 -0
  39. data/{dbdoc → docs/database}/README.md +5 -3
  40. data/{dbdoc → docs/database}/public.node_tags.md +4 -5
  41. data/docs/database/public.node_tags.svg +106 -0
  42. data/{dbdoc → docs/database}/public.nodes.md +3 -8
  43. data/docs/database/public.nodes.svg +152 -0
  44. data/docs/database/public.robot_nodes.md +44 -0
  45. data/docs/database/public.robot_nodes.svg +121 -0
  46. data/{dbdoc → docs/database}/public.robots.md +1 -2
  47. data/docs/database/public.robots.svg +106 -0
  48. data/docs/database/public.working_memories.md +40 -0
  49. data/docs/database/public.working_memories.svg +112 -0
  50. data/{dbdoc → docs/database}/schema.json +342 -110
  51. data/docs/database/schema.svg +223 -0
  52. data/docs/development/index.md +1 -29
  53. data/docs/development/schema.md +84 -324
  54. data/docs/development/testing.md +1 -9
  55. data/docs/getting-started/index.md +47 -0
  56. data/docs/{installation.md → getting-started/installation.md} +2 -2
  57. data/docs/{quick-start.md → getting-started/quick-start.md} +5 -5
  58. data/docs/guides/adding-memories.md +221 -655
  59. data/docs/guides/search-strategies.md +85 -51
  60. data/docs/images/htm-er-diagram.svg +156 -0
  61. data/docs/index.md +16 -31
  62. data/docs/multi_framework_support.md +4 -4
  63. data/examples/basic_usage.rb +18 -16
  64. data/examples/cli_app/htm_cli.rb +86 -8
  65. data/examples/custom_llm_configuration.rb +1 -2
  66. data/examples/example_app/app.rb +11 -14
  67. data/examples/sinatra_app/Gemfile +1 -0
  68. data/examples/sinatra_app/Gemfile.lock +166 -0
  69. data/examples/sinatra_app/app.rb +219 -24
  70. data/lib/htm/active_record_config.rb +10 -3
  71. data/lib/htm/configuration.rb +265 -78
  72. data/lib/htm/{sinatra.rb → integrations/sinatra.rb} +87 -12
  73. data/lib/htm/job_adapter.rb +10 -3
  74. data/lib/htm/long_term_memory.rb +220 -57
  75. data/lib/htm/models/node.rb +36 -7
  76. data/lib/htm/models/robot.rb +30 -4
  77. data/lib/htm/models/robot_node.rb +50 -0
  78. data/lib/htm/models/tag.rb +52 -0
  79. data/lib/htm/models/working_memory_entry.rb +88 -0
  80. data/lib/htm/tasks.rb +4 -0
  81. data/lib/htm/version.rb +1 -1
  82. data/lib/htm.rb +34 -13
  83. data/lib/tasks/htm.rake +32 -1
  84. data/lib/tasks/jobs.rake +7 -3
  85. data/lib/tasks/tags.rake +34 -0
  86. data/mkdocs.yml +56 -9
  87. metadata +61 -31
  88. data/dbdoc/public.node_tags.svg +0 -112
  89. data/dbdoc/public.nodes.svg +0 -118
  90. data/dbdoc/public.robots.svg +0 -90
  91. data/dbdoc/schema.svg +0 -154
  92. /data/{dbdoc → docs/database}/public.node_stats.md +0 -0
  93. /data/{dbdoc → docs/database}/public.node_stats.svg +0 -0
  94. /data/{dbdoc → docs/database}/public.nodes_tags.md +0 -0
  95. /data/{dbdoc → docs/database}/public.nodes_tags.svg +0 -0
  96. /data/{dbdoc → docs/database}/public.ontology_structure.md +0 -0
  97. /data/{dbdoc → docs/database}/public.ontology_structure.svg +0 -0
  98. /data/{dbdoc → docs/database}/public.operations_log.md +0 -0
  99. /data/{dbdoc → docs/database}/public.operations_log.svg +0 -0
  100. /data/{dbdoc → docs/database}/public.relationships.md +0 -0
  101. /data/{dbdoc → docs/database}/public.relationships.svg +0 -0
  102. /data/{dbdoc → docs/database}/public.robot_activity.md +0 -0
  103. /data/{dbdoc → docs/database}/public.robot_activity.svg +0 -0
  104. /data/{dbdoc → docs/database}/public.schema_migrations.md +0 -0
  105. /data/{dbdoc → docs/database}/public.schema_migrations.svg +0 -0
  106. /data/{dbdoc → docs/database}/public.tags.md +0 -0
  107. /data/{dbdoc → docs/database}/public.tags.svg +0 -0
  108. /data/{dbdoc → docs/database}/public.topic_relationships.md +0 -0
  109. /data/{dbdoc → docs/database}/public.topic_relationships.svg +0 -0
@@ -0,0 +1,152 @@
1
+ <svg viewBox="0 0 1000 700" xmlns="http://www.w3.org/2000/svg" style="background: transparent;">
2
+ <!-- Title -->
3
+ <text x="500" y="30" text-anchor="middle" fill="#FFFFFF" font-size="20" font-weight="bold">Memory Recall Flow (RAG-Based Retrieval)</text>
4
+
5
+ <!-- User -->
6
+ <rect x="50" y="80" width="140" height="60" fill="rgba(76, 175, 80, 0.3)" stroke="#4CAF50" stroke-width="3" rx="8"/>
7
+ <text x="120" y="115" text-anchor="middle" fill="#FFFFFF" font-size="14" font-weight="bold">User: recall</text>
8
+
9
+ <!-- HTM -->
10
+ <rect x="240" y="80" width="140" height="60" fill="rgba(33, 150, 243, 0.3)" stroke="#2196F3" stroke-width="3" rx="8"/>
11
+ <text x="310" y="115" text-anchor="middle" fill="#FFFFFF" font-size="14" font-weight="bold">HTM</text>
12
+
13
+ <!-- Parse Time -->
14
+ <rect x="430" y="80" width="180" height="60" fill="rgba(156, 39, 176, 0.3)" stroke="#9C27B0" stroke-width="3" rx="8"/>
15
+ <text x="520" y="110" text-anchor="middle" fill="#FFFFFF" font-size="13" font-weight="bold">Parse Natural</text>
16
+ <text x="520" y="130" text-anchor="middle" fill="#FFFFFF" font-size="13" font-weight="bold">Language</text>
17
+
18
+ <!-- EmbeddingService -->
19
+ <rect x="240" y="180" width="190" height="60" fill="rgba(255, 152, 0, 0.3)" stroke="#2196F3" stroke-width="3" rx="8"/>
20
+ <text x="335" y="215" text-anchor="middle" fill="#FFFFFF" font-size="14" font-weight="bold">EmbeddingService</text>
21
+
22
+ <!-- Ollama/OpenAI -->
23
+ <rect x="480" y="180" width="180" height="60" fill="rgba(255, 193, 7, 0.3)" stroke="#FFC107" stroke-width="3" rx="8"/>
24
+ <text x="570" y="215" text-anchor="middle" fill="#FFFFFF" font-size="14" font-weight="bold">Ollama/OpenAI</text>
25
+
26
+ <!-- LongTermMemory -->
27
+ <rect x="240" y="300" width="180" height="60" fill="rgba(156, 39, 176, 0.3)" stroke="#9C27B0" stroke-width="3" rx="8"/>
28
+ <text x="330" y="335" text-anchor="middle" fill="#FFFFFF" font-size="14" font-weight="bold">LongTermMemory</text>
29
+
30
+ <!-- Search Strategy Diamond -->
31
+ <polygon points="520,380 570,330 620,380 570,430" fill="rgba(255, 193, 7, 0.3)" stroke="#FFC107" stroke-width="3"/>
32
+ <text x="570" y="380" text-anchor="middle" fill="#FFFFFF" font-size="12" font-weight="bold">Search</text>
33
+ <text x="570" y="395" text-anchor="middle" fill="#FFFFFF" font-size="12" font-weight="bold">Strategy</text>
34
+
35
+ <!-- Vector Search -->
36
+ <rect x="700" y="300" width="150" height="60" fill="rgba(103, 58, 183, 0.3)" stroke="#673AB7" stroke-width="3" rx="8"/>
37
+ <text x="775" y="330" text-anchor="middle" fill="#FFFFFF" font-size="13" font-weight="bold">Vector Search</text>
38
+ <text x="775" y="348" text-anchor="middle" fill="#B0B0B0" font-size="11">(pgvector HNSW)</text>
39
+
40
+ <!-- Full-text Search -->
41
+ <rect x="700" y="380" width="150" height="60" fill="rgba(3, 169, 244, 0.3)" stroke="#03A9F4" stroke-width="3" rx="8"/>
42
+ <text x="775" y="410" text-anchor="middle" fill="#FFFFFF" font-size="13" font-weight="bold">Full-Text Search</text>
43
+ <text x="775" y="428" text-anchor="middle" fill="#B0B0B0" font-size="11">(ts_rank GIN)</text>
44
+
45
+ <!-- Hybrid Search -->
46
+ <rect x="700" y="460" width="150" height="60" fill="rgba(255, 87, 34, 0.3)" stroke="#FF5722" stroke-width="3" rx="8"/>
47
+ <text x="775" y="490" text-anchor="middle" fill="#FFFFFF" font-size="13" font-weight="bold">Hybrid Search</text>
48
+ <text x="775" y="508" text-anchor="middle" fill="#B0B0B0" font-size="11">(Hybrid + RRF)</text>
49
+
50
+ <!-- Results -->
51
+ <rect x="700" y="550" width="150" height="60" fill="rgba(76, 175, 80, 0.3)" stroke="#4CAF50" stroke-width="3" rx="8"/>
52
+ <text x="775" y="585" text-anchor="middle" fill="#FFFFFF" font-size="14" font-weight="bold">Return Results</text>
53
+
54
+ <!-- WorkingMemory -->
55
+ <rect x="240" y="550" width="180" height="60" fill="rgba(33, 150, 243, 0.3)" stroke="#2196F3" stroke-width="3" rx="8"/>
56
+ <text x="330" y="585" text-anchor="middle" fill="#FFFFFF" font-size="14" font-weight="bold">WorkingMemory</text>
57
+
58
+ <!-- Flow arrows -->
59
+ <!-- 1. Request -->
60
+ <path d="M 190 110 L 240 110" stroke="#4CAF50" stroke-width="2" fill="none" marker-end="url(#arrow1)"/>
61
+ <text x="215" y="105" text-anchor="middle" fill="#4CAF50" font-size="11">1. Request</text>
62
+
63
+ <!-- 2. Parse timeframe -->
64
+ <path d="M 380 110 L 430 110" stroke="#9C27B0" stroke-width="2" fill="none" marker-end="url(#arrow2)"/>
65
+ <text x="405" y="105" text-anchor="middle" fill="#9C27B0" font-size="11">2. Parse</text>
66
+
67
+ <!-- 3. Return range -->
68
+ <path d="M 520 140 L 520 160 L 310 160 L 310 145" stroke="#9C27B0" stroke-width="2" fill="none" marker-end="url(#arrow2)"/>
69
+ <text x="415" y="155" text-anchor="middle" fill="#9C27B0" font-size="11">3. Return range</text>
70
+
71
+ <!-- 4. Generate query embedding -->
72
+ <path d="M 310 145 L 310 180" stroke="#FF9800" stroke-width="2" fill="none" marker-end="url(#arrow3)"/>
73
+ <text x="250" y="165" text-anchor="middle" fill="#FF9800" font-size="11">4. Generate</text>
74
+ <text x="250" y="178" text-anchor="middle" fill="#FF9800" font-size="11">embedding</text>
75
+
76
+ <!-- 5. HTTP call -->
77
+ <path d="M 430 210 L 480 210" stroke="#FFC107" stroke-width="2" fill="none" marker-end="url(#arrow4)"/>
78
+ <text x="455" y="205" text-anchor="middle" fill="#FFC107" font-size="11">5. HTTP</text>
79
+
80
+ <!-- 6. Return vector -->
81
+ <path d="M 570 240 L 570 260 L 335 260 L 335 245" stroke="#FFC107" stroke-width="2" fill="none" marker-end="url(#arrow4)"/>
82
+ <text x="455" y="255" text-anchor="middle" fill="#FFC107" font-size="11">6. Return vector</text>
83
+
84
+ <!-- 7. Return embedding -->
85
+ <path d="M 285 240 L 285 280 L 310 280 L 310 265 L 310 145" stroke="#2196F3" stroke-width="2" fill="none" marker-end="url(#arrow5)"/>
86
+ <text x="255" y="265" text-anchor="middle" fill="#2196F3" font-size="11">7. embedding</text>
87
+
88
+ <!-- 8. Search -->
89
+ <path d="M 330 260 L 330 300" stroke="#9C27B0" stroke-width="2" fill="none" marker-end="url(#arrow2)"/>
90
+ <text x="345" y="285" text-anchor="middle" fill="#9C27B0" font-size="11">8. Search</text>
91
+
92
+ <!-- 9. Strategy paths -->
93
+ <path d="M 420 330 L 520 330 L 520 350 L 570 350 L 570 380" stroke="#FFC107" stroke-width="2" fill="none" marker-end="url(#arrow4)"/>
94
+
95
+ <path d="M 620 380 L 700 380 L 700 330" stroke="#673AB7" stroke-width="2" fill="none" marker-end="url(#arrow6)"/>
96
+ <text x="660" y="360" text-anchor="middle" fill="#673AB7" font-size="11">:vector</text>
97
+
98
+ <path d="M 620 390 L 700 390 L 700 410" stroke="#03A9F4" stroke-width="2" fill="none" marker-end="url(#arrow7)"/>
99
+ <text x="660" y="398" text-anchor="middle" fill="#03A9F4" font-size="11">:fulltext</text>
100
+
101
+ <path d="M 615 410 L 700 410 L 700 490" stroke="#FF5722" stroke-width="2" fill="none" marker-end="url(#arrow8)"/>
102
+ <text x="660" y="450" text-anchor="middle" fill="#FF5722" font-size="11">:hybrid</text>
103
+
104
+ <!-- 10. Return results -->
105
+ <path d="M 775 360 L 775 550" stroke="#4CAF50" stroke-width="2" fill="none" marker-end="url(#arrow1)"/>
106
+ <path d="M 775 440 L 775 550" stroke="#4CAF50" stroke-width="2" fill="none" marker-end="url(#arrow1)"/>
107
+ <path d="M 775 520 L 775 550" stroke="#4CAF50" stroke-width="2" fill="none" marker-end="url(#arrow1)"/>
108
+ <text x="795" y="475" text-anchor="start" fill="#4CAF50" font-size="11">10. Results</text>
109
+
110
+ <!-- 11. Results -->
111
+ <path d="M 700 580 L 420 580 L 420 330 L 420 360" stroke="#4CAF50" stroke-width="2" fill="none" marker-end="url(#arrow1)"/>
112
+ <text x="560" y="575" text-anchor="middle" fill="#4CAF50" font-size="11">11. Results</text>
113
+
114
+ <!-- 13. Add to WM -->
115
+ <path d="M 285 360 L 285 490 L 265 490 L 265 540 L 280 540 L 280 550" stroke="#2196F3" stroke-width="2" fill="none" marker-end="url(#arrow5)"/>
116
+ <text x="240" y="475" text-anchor="middle" fill="#2196F3" font-size="11">13. For</text>
117
+ <text x="240" y="490" text-anchor="middle" fill="#2196F3" font-size="11">each</text>
118
+ <text x="240" y="505" text-anchor="middle" fill="#2196F3" font-size="11">result</text>
119
+
120
+ <!-- 13. Return memories -->
121
+ <path d="M 240 580 L 120 580 L 120 140" stroke="#4CAF50" stroke-width="2" fill="none" marker-end="url(#arrow1)"/>
122
+ <text x="180" y="375" text-anchor="middle" fill="#4CAF50" font-size="11">13. Return</text>
123
+ <text x="180" y="390" text-anchor="middle" fill="#4CAF50" font-size="11">memories</text>
124
+
125
+ <!-- Markers -->
126
+ <defs>
127
+ <marker id="arrow1" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
128
+ <polygon points="0 0, 10 3, 0 6" fill="#4CAF50"/>
129
+ </marker>
130
+ <marker id="arrow2" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
131
+ <polygon points="0 0, 10 3, 0 6" fill="#9C27B0"/>
132
+ </marker>
133
+ <marker id="arrow3" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
134
+ <polygon points="0 0, 10 3, 0 6" fill="#FF9800"/>
135
+ </marker>
136
+ <marker id="arrow4" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
137
+ <polygon points="0 0, 10 3, 0 6" fill="#FFC107"/>
138
+ </marker>
139
+ <marker id="arrow5" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
140
+ <polygon points="0 0, 10 3, 0 6" fill="#2196F3"/>
141
+ </marker>
142
+ <marker id="arrow6" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
143
+ <polygon points="0 0, 10 3, 0 6" fill="#673AB7"/>
144
+ </marker>
145
+ <marker id="arrow7" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
146
+ <polygon points="0 0, 10 3, 0 6" fill="#03A9F4"/>
147
+ </marker>
148
+ <marker id="arrow8" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
149
+ <polygon points="0 0, 10 3, 0 6" fill="#FF5722"/>
150
+ </marker>
151
+ </defs>
152
+ </svg>
@@ -0,0 +1,123 @@
1
+ <svg viewBox="0 0 1000 700" xmlns="http://www.w3.org/2000/svg" style="background: transparent;">
2
+ <!-- Title -->
3
+ <text x="500" y="30" text-anchor="middle" fill="#FFFFFF" font-size="20" font-weight="bold">Node States in HTM</text>
4
+
5
+ <!-- Start state -->
6
+ <circle cx="100" cy="120" r="15" fill="#4CAF50" stroke="#4CAF50" stroke-width="3"/>
7
+ <circle cx="100" cy="120" r="10" fill="transparent" stroke="#4CAF50" stroke-width="3"/>
8
+
9
+ <!-- Created state -->
10
+ <rect x="220" y="90" width="160" height="60" fill="rgba(76, 175, 80, 0.3)" stroke="#4CAF50" stroke-width="3" rx="8"/>
11
+ <text x="300" y="125" text-anchor="middle" fill="#FFFFFF" font-size="14" font-weight="bold">Created</text>
12
+
13
+ <!-- InBothMemories state -->
14
+ <rect x="220" y="220" width="200" height="80" fill="rgba(33, 150, 243, 0.3)" stroke="#2196F3" stroke-width="3" rx="8"/>
15
+ <text x="320" y="250" text-anchor="middle" fill="#FFFFFF" font-size="14" font-weight="bold">InBothMemories</text>
16
+ <text x="320" y="270" text-anchor="middle" fill="#B0B0B0" font-size="11">in_working_memory=TRUE</text>
17
+ <text x="320" y="288" text-anchor="middle" fill="#B0B0B0" font-size="11">Node in WM + LTM</text>
18
+
19
+ <!-- WorkingMemoryOnly state -->
20
+ <rect x="500" y="220" width="220" height="80" fill="rgba(255, 152, 0, 0.3)" stroke="#FF9800" stroke-width="3" rx="8"/>
21
+ <text x="610" y="248" text-anchor="middle" fill="#FFFFFF" font-size="13" font-weight="bold">WorkingMemoryOnly</text>
22
+ <text x="610" y="270" text-anchor="middle" fill="#B0B0B0" font-size="11">in_working_memory=FALSE</text>
23
+ <text x="610" y="288" text-anchor="middle" fill="#B0B0B0" font-size="11">(Evicted from WM)</text>
24
+
25
+ <!-- LongTermMemoryOnly state -->
26
+ <rect x="780" y="220" width="200" height="80" fill="rgba(156, 39, 176, 0.3)" stroke="#9C27B0" stroke-width="3" rx="8"/>
27
+ <text x="880" y="248" text-anchor="middle" fill="#FFFFFF" font-size="13" font-weight="bold">LongTermMemory</text>
28
+ <text x="880" y="266" text-anchor="middle" fill="#FFFFFF" font-size="13" font-weight="bold">Only</text>
29
+ <text x="880" y="288" text-anchor="middle" fill="#B0B0B0" font-size="11">(WM cleared)</text>
30
+
31
+ <!-- Forgotten state -->
32
+ <rect x="470" y="450" width="150" height="60" fill="rgba(244, 67, 54, 0.3)" stroke="#F44336" stroke-width="3" rx="8"/>
33
+ <text x="545" y="485" text-anchor="middle" fill="#FFFFFF" font-size="14" font-weight="bold">Forgotten</text>
34
+
35
+ <!-- End state -->
36
+ <circle cx="545" cy="590" r="15" fill="transparent" stroke="#F44336" stroke-width="3"/>
37
+ <circle cx="545" cy="590" r="10" fill="#F44336"/>
38
+
39
+ <!-- Transitions -->
40
+ <!-- Start to Created -->
41
+ <path d="M 115 120 L 220 120" stroke="#4CAF50" stroke-width="2" fill="none" marker-end="url(#arrow1)"/>
42
+ <text x="167" y="115" text-anchor="middle" fill="#4CAF50" font-size="11">add_node()</text>
43
+
44
+ <!-- Created to InBothMemories -->
45
+ <path d="M 300 150 L 300 220" stroke="#2196F3" stroke-width="2" fill="none" marker-end="url(#arrow2)"/>
46
+ <text x="330" y="190" text-anchor="middle" fill="#2196F3" font-size="11">Initial state</text>
47
+
48
+ <!-- InBothMemories to WorkingMemoryOnly -->
49
+ <path d="M 420 260 L 500 260" stroke="#FF9800" stroke-width="2" fill="none" marker-end="url(#arrow3)"/>
50
+ <text x="460" y="250" text-anchor="middle" fill="#FF9800" font-size="10">Evicted</text>
51
+ <text x="460" y="263" text-anchor="middle" fill="#FF9800" font-size="10">from WM</text>
52
+
53
+ <!-- InBothMemories to LongTermMemoryOnly -->
54
+ <path d="M 420 260 Q 600 200 780 260" stroke="#9C27B0" stroke-width="2" fill="none" marker-end="url(#arrow4)"/>
55
+ <text x="600" y="220" text-anchor="middle" fill="#9C27B0" font-size="10">WM cleared</text>
56
+
57
+ <!-- WorkingMemoryOnly back to InBothMemories -->
58
+ <path d="M 610 220 Q 520 180 420 220" stroke="#4CAF50" stroke-width="2" fill="none" marker-end="url(#arrow1)"/>
59
+ <text x="520" y="185" text-anchor="middle" fill="#4CAF50" font-size="10">Recalled</text>
60
+
61
+ <!-- LongTermMemoryOnly back to InBothMemories -->
62
+ <path d="M 880 300 Q 680 360 420 300" stroke="#4CAF50" stroke-width="2" fill="none" marker-end="url(#arrow1)"/>
63
+ <text x="650" y="340" text-anchor="middle" fill="#4CAF50" font-size="10">Recalled</text>
64
+
65
+ <!-- InBothMemories to Forgotten -->
66
+ <path d="M 320 300 L 320 380 L 490 380 L 490 450" stroke="#F44336" stroke-width="2" fill="none" marker-end="url(#arrow5)"/>
67
+ <text x="390" y="375" text-anchor="middle" fill="#F44336" font-size="10">forget(confirm:</text>
68
+ <text x="390" y="388" text-anchor="middle" fill="#F44336" font-size="10">:confirmed)</text>
69
+
70
+ <!-- WorkingMemoryOnly to Forgotten -->
71
+ <path d="M 610 300 L 610 400 L 580 400 L 580 450" stroke="#F44336" stroke-width="2" fill="none" marker-end="url(#arrow5)"/>
72
+ <text x="640" y="380" text-anchor="middle" fill="#F44336" font-size="10">forget(confirm:</text>
73
+ <text x="640" y="393" text-anchor="middle" fill="#F44336" font-size="10">:confirmed)</text>
74
+
75
+ <!-- LongTermMemoryOnly to Forgotten -->
76
+ <path d="M 880 300 L 880 400 L 600 400 L 600 450" stroke="#F44336" stroke-width="2" fill="none" marker-end="url(#arrow5)"/>
77
+ <text x="740" y="395" text-anchor="middle" fill="#F44336" font-size="10">forget(confirm: :confirmed)</text>
78
+
79
+ <!-- Forgotten to End -->
80
+ <path d="M 545 510 L 545 575" stroke="#F44336" stroke-width="2" fill="none" marker-end="url(#arrow5)"/>
81
+
82
+ <!-- Notes -->
83
+ <rect x="20" y="360" width="180" height="120" fill="rgba(33, 150, 243, 0.1)" stroke="#2196F3" stroke-width="2" rx="5" stroke-dasharray="5,5"/>
84
+ <text x="110" y="380" text-anchor="middle" fill="#2196F3" font-size="12" font-weight="bold">InBothMemories</text>
85
+ <text x="110" y="400" text-anchor="middle" fill="#B0B0B0" font-size="10">Node exists in:</text>
86
+ <text x="110" y="415" text-anchor="middle" fill="#B0B0B0" font-size="10">• Working Memory</text>
87
+ <text x="110" y="430" text-anchor="middle" fill="#B0B0B0" font-size="10"> (fast access)</text>
88
+ <text x="110" y="445" text-anchor="middle" fill="#B0B0B0" font-size="10">• Long-Term Memory</text>
89
+ <text x="110" y="460" text-anchor="middle" fill="#B0B0B0" font-size="10"> (persistent)</text>
90
+ <text x="110" y="475" text-anchor="middle" fill="#4CAF50" font-size="10" font-weight="bold">in_working_memory=TRUE</text>
91
+
92
+ <rect x="700" y="400" width="180" height="90" fill="rgba(156, 39, 176, 0.1)" stroke="#9C27B0" stroke-width="2" rx="5" stroke-dasharray="5,5"/>
93
+ <text x="790" y="420" text-anchor="middle" fill="#9C27B0" font-size="12" font-weight="bold">LTM Only</text>
94
+ <text x="790" y="440" text-anchor="middle" fill="#B0B0B0" font-size="10">Node exists only in:</text>
95
+ <text x="790" y="455" text-anchor="middle" fill="#B0B0B0" font-size="10">• Long-Term Memory</text>
96
+ <text x="790" y="475" text-anchor="middle" fill="#F44336" font-size="10" font-weight="bold">in_working_memory=FALSE</text>
97
+ <text x="790" y="487" text-anchor="middle" fill="#B0B0B0" font-size="9">(Evicted due to token limit)</text>
98
+
99
+ <rect x="630" y="600" width="180" height="80" fill="rgba(244, 67, 54, 0.1)" stroke="#F44336" stroke-width="2" rx="5" stroke-dasharray="5,5"/>
100
+ <text x="720" y="620" text-anchor="middle" fill="#F44336" font-size="12" font-weight="bold">Forgotten</text>
101
+ <text x="720" y="640" text-anchor="middle" fill="#B0B0B0" font-size="10">Node permanently</text>
102
+ <text x="720" y="655" text-anchor="middle" fill="#B0B0B0" font-size="10">deleted from both</text>
103
+ <text x="720" y="670" text-anchor="middle" fill="#B0B0B0" font-size="10">memories</text>
104
+
105
+ <!-- Markers -->
106
+ <defs>
107
+ <marker id="arrow1" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
108
+ <polygon points="0 0, 10 3, 0 6" fill="#4CAF50"/>
109
+ </marker>
110
+ <marker id="arrow2" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
111
+ <polygon points="0 0, 10 3, 0 6" fill="#2196F3"/>
112
+ </marker>
113
+ <marker id="arrow3" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
114
+ <polygon points="0 0, 10 3, 0 6" fill="#FF9800"/>
115
+ </marker>
116
+ <marker id="arrow4" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
117
+ <polygon points="0 0, 10 3, 0 6" fill="#9C27B0"/>
118
+ </marker>
119
+ <marker id="arrow5" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
120
+ <polygon points="0 0, 10 3, 0 6" fill="#F44336"/>
121
+ </marker>
122
+ </defs>
123
+ </svg>
@@ -0,0 +1,78 @@
1
+ <svg viewBox="0 0 800 900" xmlns="http://www.w3.org/2000/svg" style="background: transparent;">
2
+ <!-- Title -->
3
+ <text x="400" y="30" text-anchor="middle" fill="#FFFFFF" font-size="20" font-weight="bold">HTM Project Structure</text>
4
+
5
+ <!-- Root -->
6
+ <text x="50" y="70" fill="#4CAF50" font-size="14" font-weight="bold">htm/</text>
7
+
8
+ <!-- lib/ -->
9
+ <text x="70" y="100" fill="#2196F3" font-size="13" font-weight="bold">├── lib/</text>
10
+ <text x="250" y="100" fill="#B0B0B0" font-size="11">Main library code</text>
11
+ <text x="90" y="125" fill="#FF9800" font-size="12">├── htm.rb</text>
12
+ <text x="250" y="125" fill="#B0B0B0" font-size="10">HTM main class</text>
13
+ <text x="90" y="150" fill="#FF9800" font-size="12">└── htm/</text>
14
+ <text x="120" y="175" fill="#FFC107" font-size="11">├── database.rb</text>
15
+ <text x="300" y="175" fill="#B0B0B0" font-size="10">Database setup and management</text>
16
+ <text x="120" y="200" fill="#FFC107" font-size="11">├── long_term_memory.rb</text>
17
+ <text x="300" y="200" fill="#B0B0B0" font-size="10">PostgreSQL-backed storage</text>
18
+ <text x="120" y="225" fill="#FFC107" font-size="11">├── working_memory.rb</text>
19
+ <text x="300" y="225" fill="#B0B0B0" font-size="10">In-memory active context</text>
20
+ <text x="120" y="250" fill="#FFC107" font-size="11">├── embedding_service.rb</text>
21
+ <text x="300" y="250" fill="#B0B0B0" font-size="10">Vector embedding generation</text>
22
+ <text x="120" y="275" fill="#FFC107" font-size="11">└── version.rb</text>
23
+ <text x="300" y="275" fill="#B0B0B0" font-size="10">Version constant</text>
24
+
25
+ <!-- test/ -->
26
+ <text x="70" y="310" fill="#2196F3" font-size="13" font-weight="bold">├── test/</text>
27
+ <text x="250" y="310" fill="#B0B0B0" font-size="11">Test suite</text>
28
+ <text x="90" y="335" fill="#FF9800" font-size="12">├── test_helper.rb</text>
29
+ <text x="300" y="335" fill="#B0B0B0" font-size="10">Test configuration</text>
30
+ <text x="90" y="360" fill="#FF9800" font-size="12">├── htm_test.rb</text>
31
+ <text x="300" y="360" fill="#B0B0B0" font-size="10">Unit tests</text>
32
+ <text x="90" y="385" fill="#FF9800" font-size="12">├── embedding_service_test.rb</text>
33
+ <text x="300" y="385" fill="#B0B0B0" font-size="10">Embedding tests</text>
34
+ <text x="90" y="410" fill="#FF9800" font-size="12">└── integration_test.rb</text>
35
+ <text x="300" y="410" fill="#B0B0B0" font-size="10">Integration tests</text>
36
+
37
+ <!-- sql/ -->
38
+ <text x="70" y="445" fill="#2196F3" font-size="13" font-weight="bold">├── sql/</text>
39
+ <text x="250" y="445" fill="#B0B0B0" font-size="11">Database schemas</text>
40
+ <text x="90" y="470" fill="#FF9800" font-size="12">└── schema.sql</text>
41
+ <text x="300" y="470" fill="#B0B0B0" font-size="10">PostgreSQL schema</text>
42
+
43
+ <!-- examples/ -->
44
+ <text x="70" y="505" fill="#2196F3" font-size="13" font-weight="bold">├── examples/</text>
45
+ <text x="250" y="505" fill="#B0B0B0" font-size="11">Usage examples</text>
46
+ <text x="90" y="530" fill="#FF9800" font-size="12">└── basic_usage.rb</text>
47
+ <text x="300" y="530" fill="#B0B0B0" font-size="10">Basic usage demonstration</text>
48
+
49
+ <!-- docs/ -->
50
+ <text x="70" y="565" fill="#2196F3" font-size="13" font-weight="bold">├── docs/</text>
51
+ <text x="250" y="565" fill="#B0B0B0" font-size="11">Documentation (MkDocs)</text>
52
+ <text x="90" y="590" fill="#FF9800" font-size="12">├── development/</text>
53
+ <text x="300" y="590" fill="#B0B0B0" font-size="10">This guide</text>
54
+ <text x="90" y="615" fill="#FF9800" font-size="12">├── guides/</text>
55
+ <text x="300" y="615" fill="#B0B0B0" font-size="10">User guides</text>
56
+ <text x="90" y="640" fill="#FF9800" font-size="12">├── api/</text>
57
+ <text x="300" y="640" fill="#B0B0B0" font-size="10">API reference</text>
58
+ <text x="90" y="665" fill="#FF9800" font-size="12">└── architecture/</text>
59
+ <text x="300" y="665" fill="#B0B0B0" font-size="10">Architecture docs</text>
60
+
61
+ <!-- Root files -->
62
+ <text x="70" y="700" fill="#2196F3" font-size="13" font-weight="bold">├── Rakefile</text>
63
+ <text x="250" y="700" fill="#B0B0B0" font-size="11">Rake tasks</text>
64
+ <text x="70" y="725" fill="#2196F3" font-size="13" font-weight="bold">├── Gemfile</text>
65
+ <text x="250" y="725" fill="#B0B0B0" font-size="11">Development dependencies</text>
66
+ <text x="70" y="750" fill="#2196F3" font-size="13" font-weight="bold">├── htm.gemspec</text>
67
+ <text x="250" y="750" fill="#B0B0B0" font-size="11">Gem specification</text>
68
+ <text x="70" y="775" fill="#2196F3" font-size="13" font-weight="bold">└── README.md</text>
69
+ <text x="250" y="775" fill="#B0B0B0" font-size="11">Project overview</text>
70
+
71
+ <!-- Legend -->
72
+ <rect x="30" y="810" width="740" height="70" fill="rgba(33, 150, 243, 0.1)" stroke="#2196F3" stroke-width="2" rx="5" stroke-dasharray="5,5"/>
73
+ <text x="400" y="830" text-anchor="middle" fill="#2196F3" font-size="12" font-weight="bold">Directory Structure Key</text>
74
+ <text x="50" y="850" fill="#B0B0B0" font-size="10">• <tspan fill="#4CAF50" font-weight="bold">Green</tspan>: Root directory</text>
75
+ <text x="250" y="850" fill="#B0B0B0" font-size="10">• <tspan fill="#2196F3" font-weight="bold">Blue</tspan>: Directories &amp; root files</text>
76
+ <text x="500" y="850" fill="#B0B0B0" font-size="10">• <tspan fill="#FF9800" font-weight="bold">Orange/Yellow</tspan>: Files</text>
77
+ <text x="50" y="870" fill="#B0B0B0" font-size="10">• <tspan fill="#B0B0B0">Gray</tspan>: Descriptions</text>
78
+ </svg>
@@ -0,0 +1,38 @@
1
+ <svg viewBox="0 0 700 400" xmlns="http://www.w3.org/2000/svg" style="background: transparent;">
2
+ <!-- Title -->
3
+ <text x="350" y="30" text-anchor="middle" fill="#FFFFFF" font-size="18" font-weight="bold">Test Directory Structure</text>
4
+
5
+ <!-- Root -->
6
+ <text x="100" y="80" fill="#4CAF50" font-size="14" font-weight="bold">test/</text>
7
+
8
+ <!-- test_helper.rb -->
9
+ <text x="120" y="120" fill="#2196F3" font-size="13">├── test_helper.rb</text>
10
+ <text x="350" y="120" fill="#B0B0B0" font-size="11">Shared test configuration</text>
11
+
12
+ <!-- htm_test.rb -->
13
+ <text x="120" y="155" fill="#2196F3" font-size="13">├── htm_test.rb</text>
14
+ <text x="350" y="155" fill="#B0B0B0" font-size="11">Unit tests for HTM class</text>
15
+
16
+ <!-- embedding_service_test.rb -->
17
+ <text x="120" y="190" fill="#2196F3" font-size="13">├── embedding_service_test.rb</text>
18
+ <text x="350" y="190" fill="#B0B0B0" font-size="11">Unit tests for EmbeddingService</text>
19
+
20
+ <!-- integration_test.rb -->
21
+ <text x="120" y="225" fill="#2196F3" font-size="13">├── integration_test.rb</text>
22
+ <text x="350" y="225" fill="#B0B0B0" font-size="11">Integration tests</text>
23
+
24
+ <!-- fixtures/ -->
25
+ <text x="120" y="260" fill="#9C27B0" font-size="13">└── fixtures/</text>
26
+ <text x="350" y="260" fill="#B0B0B0" font-size="11">Test data (future)</text>
27
+
28
+ <!-- sample_memories.json -->
29
+ <text x="160" y="295" fill="#FF9800" font-size="12">└── sample_memories.json</text>
30
+ <text x="400" y="295" fill="#B0B0B0" font-size="10">Sample test data</text>
31
+
32
+ <!-- Legend -->
33
+ <rect x="50" y="330" width="600" height="50" fill="rgba(33, 150, 243, 0.1)" stroke="#2196F3" stroke-width="2" rx="5" stroke-dasharray="5,5"/>
34
+ <text x="350" y="350" text-anchor="middle" fill="#2196F3" font-size="12" font-weight="bold">Test Suite Components</text>
35
+ <text x="70" y="370" fill="#B0B0B0" font-size="10">• <tspan fill="#4CAF50" font-weight="bold">Green</tspan>: Root directory</text>
36
+ <text x="250" y="370" fill="#B0B0B0" font-size="10">• <tspan fill="#2196F3" font-weight="bold">Blue</tspan>: Test files</text>
37
+ <text x="450" y="370" fill="#B0B0B0" font-size="10">• <tspan fill="#9C27B0" font-weight="bold">Purple</tspan>: Subdirectories</text>
38
+ </svg>
@@ -4,11 +4,13 @@
4
4
 
5
5
  | Name | Columns | Comment | Type |
6
6
  | ---- | ------- | ------- | ---- |
7
- | [public.node_tags](public.node_tags.md) | 4 | Join table connecting nodes to tags (many-to-many) | BASE TABLE |
7
+ | [public.robot_nodes](public.robot_nodes.md) | 8 | Join table connecting robots to nodes (many-to-many) | BASE TABLE |
8
8
  | [public.schema_migrations](public.schema_migrations.md) | 1 | | BASE TABLE |
9
- | [public.robots](public.robots.md) | 5 | Registry of all LLM robots using the HTM system | BASE TABLE |
10
- | [public.nodes](public.nodes.md) | 12 | Core memory storage for conversation messages and context | BASE TABLE |
9
+ | [public.robots](public.robots.md) | 4 | Registry of all LLM robots using the HTM system | BASE TABLE |
10
+ | [public.nodes](public.nodes.md) | 10 | Core memory storage for conversation messages and context | BASE TABLE |
11
11
  | [public.tags](public.tags.md) | 3 | Unique tag names for categorization | BASE TABLE |
12
+ | [public.node_tags](public.node_tags.md) | 4 | Join table connecting nodes to tags (many-to-many) | BASE TABLE |
13
+ | [public.working_memories](public.working_memories.md) | 5 | Per-robot working memory state (optional persistence) | BASE TABLE |
12
14
 
13
15
  ## Stored procedures and functions
14
16
 
@@ -9,18 +9,17 @@ Join table connecting nodes to tags (many-to-many)
9
9
  | Name | Type | Default | Nullable | Children | Parents | Comment |
10
10
  | ---- | ---- | ------- | -------- | -------- | ------- | ------- |
11
11
  | id | bigint | nextval('node_tags_id_seq'::regclass) | false | | | |
12
- | node_id | bigint | | false | | [public.nodes](public.nodes.md) | |
13
- | tag_id | bigint | | false | | [public.tags](public.tags.md) | |
14
- | created_at | timestamp with time zone | CURRENT_TIMESTAMP | true | | | |
12
+ | node_id | bigint | | false | | [public.nodes](public.nodes.md) | ID of the node being tagged |
13
+ | tag_id | bigint | | false | | [public.tags](public.tags.md) | ID of the tag being applied |
14
+ | created_at | timestamp with time zone | CURRENT_TIMESTAMP | true | | | When this association was created |
15
15
 
16
16
  ## Constraints
17
17
 
18
18
  | Name | Type | Definition |
19
19
  | ---- | ---- | ---------- |
20
- | node_tags_pkey | PRIMARY KEY | PRIMARY KEY (id) |
21
- | idx_node_tags_unique | UNIQUE | UNIQUE (node_id, tag_id) |
22
20
  | fk_rails_ebc9aafd9f | FOREIGN KEY | FOREIGN KEY (node_id) REFERENCES nodes(id) ON DELETE CASCADE |
23
21
  | fk_rails_b51cdcc57f | FOREIGN KEY | FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE |
22
+ | node_tags_pkey | PRIMARY KEY | PRIMARY KEY (id) |
24
23
 
25
24
  ## Indexes
26
25
 
@@ -0,0 +1,106 @@
1
+ <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3
+ "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4
+ <!-- Generated by graphviz version 12.1.2 (20240928.0832)
5
+ -->
6
+ <!-- Title: public.node_tags Pages: 1 -->
7
+ <svg width="961pt" height="725pt"
8
+ viewBox="0.00 0.00 961.37 725.20" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
9
+ <g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 721.2)">
10
+ <title>public.node_tags</title>
11
+ <polygon fill="white" stroke="none" points="-4,4 -4,-721.2 957.37,-721.2 957.37,4 -4,4"/>
12
+ <!-- public.node_tags -->
13
+ <g id="node1" class="node">
14
+ <title>public.node_tags</title>
15
+ <polygon fill="#efefef" stroke="none" points="354.55,-635.4 354.55,-671 615.51,-671 615.51,-635.4 354.55,-635.4"/>
16
+ <polygon fill="none" stroke="black" points="354.55,-635.4 354.55,-671 615.51,-671 615.51,-635.4 354.55,-635.4"/>
17
+ <text text-anchor="start" x="361.55" y="-648.8" font-family="Arial Bold" font-size="18.00">public.node_tags</text>
18
+ <text text-anchor="start" x="484.02" y="-648.8" font-family="Arial" font-size="14.00">    </text>
19
+ <text text-anchor="start" x="515.14" y="-648.8" font-family="Arial" font-size="14.00" fill="#666666">[BASE TABLE]</text>
20
+ <polygon fill="none" stroke="black" points="354.55,-604.6 354.55,-635.4 615.51,-635.4 615.51,-604.6 354.55,-604.6"/>
21
+ <text text-anchor="start" x="361.55" y="-616.8" font-family="Arial" font-size="14.00">id </text>
22
+ <text text-anchor="start" x="376.33" y="-616.8" font-family="Arial" font-size="14.00" fill="#666666">[bigint]</text>
23
+ <polygon fill="none" stroke="black" points="354.55,-573.8 354.55,-604.6 615.51,-604.6 615.51,-573.8 354.55,-573.8"/>
24
+ <text text-anchor="start" x="361.55" y="-586" font-family="Arial" font-size="14.00">node_id </text>
25
+ <text text-anchor="start" x="415.26" y="-586" font-family="Arial" font-size="14.00" fill="#666666">[bigint]</text>
26
+ <polygon fill="none" stroke="black" points="354.55,-543 354.55,-573.8 615.51,-573.8 615.51,-543 354.55,-543"/>
27
+ <text text-anchor="start" x="361.55" y="-555.2" font-family="Arial" font-size="14.00">tag_id </text>
28
+ <text text-anchor="start" x="403.58" y="-555.2" font-family="Arial" font-size="14.00" fill="#666666">[bigint]</text>
29
+ <polygon fill="none" stroke="black" points="354.55,-512.2 354.55,-543 615.51,-543 615.51,-512.2 354.55,-512.2"/>
30
+ <text text-anchor="start" x="361.55" y="-524.4" font-family="Arial" font-size="14.00">created_at </text>
31
+ <text text-anchor="start" x="431.59" y="-524.4" font-family="Arial" font-size="14.00" fill="#666666">[timestamp with time zone]</text>
32
+ <polygon fill="none" stroke="black" stroke-width="3" points="353.05,-510.7 353.05,-672.5 617.01,-672.5 617.01,-510.7 353.05,-510.7"/>
33
+ </g>
34
+ <!-- public.nodes -->
35
+ <g id="node2" class="node">
36
+ <title>public.nodes</title>
37
+ <polygon fill="#efefef" stroke="none" points="166.86,-351.2 166.86,-386.8 439.19,-386.8 439.19,-351.2 166.86,-351.2"/>
38
+ <polygon fill="none" stroke="black" points="166.86,-351.2 166.86,-386.8 439.19,-386.8 439.19,-351.2 166.86,-351.2"/>
39
+ <text text-anchor="start" x="195.04" y="-364.6" font-family="Arial Bold" font-size="18.00">public.nodes</text>
40
+ <text text-anchor="start" x="286.53" y="-364.6" font-family="Arial" font-size="14.00">    </text>
41
+ <text text-anchor="start" x="317.64" y="-364.6" font-family="Arial" font-size="14.00" fill="#666666">[BASE TABLE]</text>
42
+ <polygon fill="none" stroke="black" points="166.86,-320.4 166.86,-351.2 439.19,-351.2 439.19,-320.4 166.86,-320.4"/>
43
+ <text text-anchor="start" x="173.86" y="-332.6" font-family="Arial" font-size="14.00">id </text>
44
+ <text text-anchor="start" x="188.65" y="-332.6" font-family="Arial" font-size="14.00" fill="#666666">[bigint]</text>
45
+ <polygon fill="none" stroke="black" points="166.86,-289.6 166.86,-320.4 439.19,-320.4 439.19,-289.6 166.86,-289.6"/>
46
+ <text text-anchor="start" x="173.86" y="-301.8" font-family="Arial" font-size="14.00">content </text>
47
+ <text text-anchor="start" x="223.68" y="-301.8" font-family="Arial" font-size="14.00" fill="#666666">[text]</text>
48
+ <polygon fill="none" stroke="black" points="166.86,-258.8 166.86,-289.6 439.19,-289.6 439.19,-258.8 166.86,-258.8"/>
49
+ <text text-anchor="start" x="173.86" y="-271" font-family="Arial" font-size="14.00">access_count </text>
50
+ <text text-anchor="start" x="263.36" y="-271" font-family="Arial" font-size="14.00" fill="#666666">[integer]</text>
51
+ <polygon fill="none" stroke="black" points="166.86,-228 166.86,-258.8 439.19,-258.8 439.19,-228 166.86,-228"/>
52
+ <text text-anchor="start" x="173.86" y="-240.2" font-family="Arial" font-size="14.00">created_at </text>
53
+ <text text-anchor="start" x="243.91" y="-240.2" font-family="Arial" font-size="14.00" fill="#666666">[timestamp with time zone]</text>
54
+ <polygon fill="none" stroke="black" points="166.86,-197.2 166.86,-228 439.19,-228 439.19,-197.2 166.86,-197.2"/>
55
+ <text text-anchor="start" x="173.86" y="-209.4" font-family="Arial" font-size="14.00">updated_at </text>
56
+ <text text-anchor="start" x="247.82" y="-209.4" font-family="Arial" font-size="14.00" fill="#666666">[timestamp with time zone]</text>
57
+ <polygon fill="none" stroke="black" points="166.86,-166.4 166.86,-197.2 439.19,-197.2 439.19,-166.4 166.86,-166.4"/>
58
+ <text text-anchor="start" x="173.86" y="-178.6" font-family="Arial" font-size="14.00">last_accessed </text>
59
+ <text text-anchor="start" x="266.47" y="-178.6" font-family="Arial" font-size="14.00" fill="#666666">[timestamp with time zone]</text>
60
+ <polygon fill="none" stroke="black" points="166.86,-135.6 166.86,-166.4 439.19,-166.4 439.19,-135.6 166.86,-135.6"/>
61
+ <text text-anchor="start" x="173.86" y="-147.8" font-family="Arial" font-size="14.00">token_count </text>
62
+ <text text-anchor="start" x="254.04" y="-147.8" font-family="Arial" font-size="14.00" fill="#666666">[integer]</text>
63
+ <polygon fill="none" stroke="black" points="166.86,-104.8 166.86,-135.6 439.19,-135.6 439.19,-104.8 166.86,-104.8"/>
64
+ <text text-anchor="start" x="173.86" y="-117" font-family="Arial" font-size="14.00">embedding </text>
65
+ <text text-anchor="start" x="247.03" y="-117" font-family="Arial" font-size="14.00" fill="#666666">[vector(2000)]</text>
66
+ <polygon fill="none" stroke="black" points="166.86,-74 166.86,-104.8 439.19,-104.8 439.19,-74 166.86,-74"/>
67
+ <text text-anchor="start" x="173.86" y="-86.2" font-family="Arial" font-size="14.00">embedding_dimension </text>
68
+ <text text-anchor="start" x="318.63" y="-86.2" font-family="Arial" font-size="14.00" fill="#666666">[integer]</text>
69
+ <polygon fill="none" stroke="black" points="166.86,-43.2 166.86,-74 439.19,-74 439.19,-43.2 166.86,-43.2"/>
70
+ <text text-anchor="start" x="173.86" y="-55.4" font-family="Arial" font-size="14.00">content_hash </text>
71
+ <text text-anchor="start" x="261.82" y="-55.4" font-family="Arial" font-size="14.00" fill="#666666">[varchar(64)]</text>
72
+ </g>
73
+ <!-- public.node_tags&#45;&gt;public.nodes -->
74
+ <g id="edge1" class="edge">
75
+ <title>public.node_tags:node_id&#45;&gt;public.nodes:id</title>
76
+ <path fill="none" stroke="black" d="M343.42,-588.15C302.28,-578.73 326.23,-508.44 354.55,-466 377.24,-431.99 416.46,-463.98 439.19,-430 462.48,-395.2 482.06,-335.8 440.19,-335.8"/>
77
+ <polygon fill="black" stroke="black" points="343.27,-588.13 352.75,-593.64 348.57,-588.68 352.88,-589.13 352.88,-589.13 352.88,-589.13 348.57,-588.68 353.68,-584.69 343.27,-588.13"/>
78
+ <text text-anchor="start" x="7" y="-599.2" font-family="Arial" font-size="10.00">FOREIGN KEY (node_id) REFERENCES nodes(id) ON DELETE CASCADE</text>
79
+ </g>
80
+ <!-- public.tags -->
81
+ <g id="node3" class="node">
82
+ <title>public.tags</title>
83
+ <polygon fill="#efefef" stroke="none" points="543.14,-243.4 543.14,-279 792.91,-279 792.91,-243.4 543.14,-243.4"/>
84
+ <polygon fill="none" stroke="black" points="543.14,-243.4 543.14,-279 792.91,-279 792.91,-243.4 543.14,-243.4"/>
85
+ <text text-anchor="start" x="566.54" y="-256.8" font-family="Arial Bold" font-size="18.00">public.tags</text>
86
+ <text text-anchor="start" x="645.03" y="-256.8" font-family="Arial" font-size="14.00">    </text>
87
+ <text text-anchor="start" x="676.14" y="-256.8" font-family="Arial" font-size="14.00" fill="#666666">[BASE TABLE]</text>
88
+ <polygon fill="none" stroke="black" points="543.14,-212.6 543.14,-243.4 792.91,-243.4 792.91,-212.6 543.14,-212.6"/>
89
+ <text text-anchor="start" x="550.14" y="-224.8" font-family="Arial" font-size="14.00">id </text>
90
+ <text text-anchor="start" x="564.93" y="-224.8" font-family="Arial" font-size="14.00" fill="#666666">[bigint]</text>
91
+ <polygon fill="none" stroke="black" points="543.14,-181.8 543.14,-212.6 792.91,-212.6 792.91,-181.8 543.14,-181.8"/>
92
+ <text text-anchor="start" x="550.14" y="-194" font-family="Arial" font-size="14.00">name </text>
93
+ <text text-anchor="start" x="589.05" y="-194" font-family="Arial" font-size="14.00" fill="#666666">[text]</text>
94
+ <polygon fill="none" stroke="black" points="543.14,-151 543.14,-181.8 792.91,-181.8 792.91,-151 543.14,-151"/>
95
+ <text text-anchor="start" x="550.14" y="-163.2" font-family="Arial" font-size="14.00">created_at </text>
96
+ <text text-anchor="start" x="620.19" y="-163.2" font-family="Arial" font-size="14.00" fill="#666666">[timestamp with time zone]</text>
97
+ </g>
98
+ <!-- public.node_tags&#45;&gt;public.tags -->
99
+ <g id="edge2" class="edge">
100
+ <title>public.node_tags:tag_id&#45;&gt;public.tags:id</title>
101
+ <path fill="none" stroke="black" d="M626.61,-557.82C749.01,-542.46 395.3,-228 542.14,-228"/>
102
+ <polygon fill="black" stroke="black" points="626.83,-557.81 616.59,-553.89 621.5,-558.11 617.18,-558.36 617.18,-558.36 617.18,-558.36 621.5,-558.11 617.1,-562.87 626.83,-557.81"/>
103
+ <text text-anchor="start" x="623.51" y="-568.4" font-family="Arial" font-size="10.00">FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE</text>
104
+ </g>
105
+ </g>
106
+ </svg>
@@ -8,25 +8,22 @@ Core memory storage for conversation messages and context
8
8
 
9
9
  | Name | Type | Default | Nullable | Children | Parents | Comment |
10
10
  | ---- | ---- | ------- | -------- | -------- | ------- | ------- |
11
- | id | bigint | nextval('nodes_id_seq'::regclass) | false | [public.node_tags](public.node_tags.md) | | |
11
+ | id | bigint | nextval('nodes_id_seq'::regclass) | false | [public.robot_nodes](public.robot_nodes.md) [public.node_tags](public.node_tags.md) [public.working_memories](public.working_memories.md) | | |
12
12
  | content | text | | false | | | The conversation message/utterance content |
13
- | source | text | ''::text | true | | | From where the content came (empty string if unknown) |
14
13
  | access_count | integer | 0 | false | | | Number of times this node has been accessed/retrieved |
15
14
  | created_at | timestamp with time zone | CURRENT_TIMESTAMP | true | | | When this memory was created |
16
15
  | updated_at | timestamp with time zone | CURRENT_TIMESTAMP | true | | | When this memory was last modified |
17
16
  | last_accessed | timestamp with time zone | CURRENT_TIMESTAMP | true | | | When this memory was last accessed |
18
17
  | token_count | integer | | true | | | Number of tokens in the content (for context budget management) |
19
- | in_working_memory | boolean | false | true | | | Whether this memory is currently in working memory |
20
- | robot_id | bigint | | false | | [public.robots](public.robots.md) | ID of the robot that owns this memory |
21
18
  | embedding | vector(2000) | | true | | | Vector embedding (max 2000 dimensions) for semantic search |
22
19
  | embedding_dimension | integer | | true | | | Actual number of dimensions used in the embedding vector (max 2000) |
20
+ | content_hash | varchar(64) | | true | | | SHA-256 hash of content for deduplication |
23
21
 
24
22
  ## Constraints
25
23
 
26
24
  | Name | Type | Definition |
27
25
  | ---- | ---- | ---------- |
28
26
  | check_embedding_dimension | CHECK | CHECK (((embedding_dimension IS NULL) OR ((embedding_dimension > 0) AND (embedding_dimension <= 2000)))) |
29
- | fk_rails_60162e9d3a | FOREIGN KEY | FOREIGN KEY (robot_id) REFERENCES robots(id) ON DELETE CASCADE |
30
27
  | nodes_pkey | PRIMARY KEY | PRIMARY KEY (id) |
31
28
 
32
29
  ## Indexes
@@ -38,12 +35,10 @@ Core memory storage for conversation messages and context
38
35
  | idx_nodes_updated_at | CREATE INDEX idx_nodes_updated_at ON public.nodes USING btree (updated_at) |
39
36
  | idx_nodes_last_accessed | CREATE INDEX idx_nodes_last_accessed ON public.nodes USING btree (last_accessed) |
40
37
  | idx_nodes_access_count | CREATE INDEX idx_nodes_access_count ON public.nodes USING btree (access_count) |
41
- | idx_nodes_robot_id | CREATE INDEX idx_nodes_robot_id ON public.nodes USING btree (robot_id) |
42
- | idx_nodes_source | CREATE INDEX idx_nodes_source ON public.nodes USING btree (source) |
43
- | idx_nodes_in_working_memory | CREATE INDEX idx_nodes_in_working_memory ON public.nodes USING btree (in_working_memory) |
44
38
  | idx_nodes_embedding | CREATE INDEX idx_nodes_embedding ON public.nodes USING hnsw (embedding vector_cosine_ops) WITH (m='16', ef_construction='64') |
45
39
  | idx_nodes_content_gin | CREATE INDEX idx_nodes_content_gin ON public.nodes USING gin (to_tsvector('english'::regconfig, content)) |
46
40
  | idx_nodes_content_trgm | CREATE INDEX idx_nodes_content_trgm ON public.nodes USING gin (content gin_trgm_ops) |
41
+ | idx_nodes_content_hash_unique | CREATE UNIQUE INDEX idx_nodes_content_hash_unique ON public.nodes USING btree (content_hash) |
47
42
 
48
43
  ## Relations
49
44