htm 0.0.15 → 0.0.18
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/.architecture/decisions/adrs/001-use-postgresql-timescaledb-storage.md +1 -1
- data/.architecture/decisions/adrs/011-database-side-embedding-generation-with-pgai.md +4 -4
- data/.architecture/decisions/adrs/012-llm-driven-ontology-topic-extraction.md +1 -1
- data/.envrc +12 -24
- data/.irbrc +7 -7
- data/.tbls.yml +2 -2
- data/CHANGELOG.md +138 -0
- data/README.md +97 -1592
- data/Rakefile +8 -3
- data/SETUP.md +12 -12
- data/bin/htm_mcp +27 -0
- data/db/seed_data/README.md +2 -2
- data/db/seeds.rb +2 -2
- data/docs/api/database.md +37 -37
- data/docs/api/htm.md +1 -1
- data/docs/api/yard/HTM/ActiveRecordConfig.md +2 -2
- data/docs/api/yard/HTM/Configuration.md +26 -15
- data/docs/api/yard/HTM/Database.md +7 -8
- data/docs/api/yard/HTM/JobAdapter.md +1 -1
- data/docs/api/yard/HTM/Railtie.md +2 -2
- data/docs/architecture/adrs/001-postgresql-timescaledb.md +1 -1
- data/docs/architecture/adrs/011-pgai-integration.md +4 -4
- data/docs/database_rake_tasks.md +5 -5
- data/docs/development/rake-tasks.md +11 -11
- data/docs/development/setup.md +21 -21
- data/docs/development/testing.md +1 -1
- data/docs/getting-started/installation.md +51 -31
- data/docs/getting-started/quick-start.md +12 -12
- data/docs/guides/getting-started.md +2 -2
- data/docs/guides/long-term-memory.md +1 -1
- data/docs/guides/mcp-server.md +464 -29
- data/docs/guides/robot-groups.md +8 -8
- data/docs/index.md +4 -4
- data/docs/multi_framework_support.md +10 -10
- data/docs/setup_local_database.md +19 -19
- data/docs/using_rake_tasks_in_your_app.md +14 -14
- data/examples/README.md +50 -6
- data/examples/basic_usage.rb +31 -21
- data/examples/cli_app/README.md +8 -8
- data/examples/cli_app/htm_cli.rb +5 -5
- data/examples/config_file_example/README.md +256 -0
- data/examples/config_file_example/config/htm.local.yml +34 -0
- data/examples/config_file_example/custom_config.yml +22 -0
- data/examples/config_file_example/show_config.rb +125 -0
- data/examples/custom_llm_configuration.rb +7 -7
- data/examples/example_app/Rakefile +2 -2
- data/examples/example_app/app.rb +8 -8
- data/examples/file_loader_usage.rb +9 -9
- data/examples/mcp_client.rb +7 -7
- data/examples/rails_app/.gitignore +2 -0
- data/examples/rails_app/Gemfile +22 -0
- data/examples/rails_app/Gemfile.lock +430 -0
- data/examples/rails_app/Procfile.dev +1 -0
- data/examples/rails_app/README.md +98 -0
- data/examples/rails_app/Rakefile +5 -0
- data/examples/rails_app/app/assets/stylesheets/application.css +83 -0
- data/examples/rails_app/app/assets/stylesheets/inter-font.css +6 -0
- data/examples/rails_app/app/controllers/application_controller.rb +19 -0
- data/examples/rails_app/app/controllers/dashboard_controller.rb +27 -0
- data/examples/rails_app/app/controllers/files_controller.rb +205 -0
- data/examples/rails_app/app/controllers/memories_controller.rb +102 -0
- data/examples/rails_app/app/controllers/robots_controller.rb +44 -0
- data/examples/rails_app/app/controllers/search_controller.rb +46 -0
- data/examples/rails_app/app/controllers/tags_controller.rb +30 -0
- data/examples/rails_app/app/javascript/application.js +4 -0
- data/examples/rails_app/app/javascript/controllers/application.js +9 -0
- data/examples/rails_app/app/javascript/controllers/index.js +6 -0
- data/examples/rails_app/app/views/dashboard/index.html.erb +123 -0
- data/examples/rails_app/app/views/files/index.html.erb +108 -0
- data/examples/rails_app/app/views/files/new.html.erb +321 -0
- data/examples/rails_app/app/views/files/show.html.erb +130 -0
- data/examples/rails_app/app/views/layouts/application.html.erb +124 -0
- data/examples/rails_app/app/views/memories/_memory_card.html.erb +51 -0
- data/examples/rails_app/app/views/memories/deleted.html.erb +62 -0
- data/examples/rails_app/app/views/memories/edit.html.erb +35 -0
- data/examples/rails_app/app/views/memories/index.html.erb +81 -0
- data/examples/rails_app/app/views/memories/new.html.erb +71 -0
- data/examples/rails_app/app/views/memories/show.html.erb +126 -0
- data/examples/rails_app/app/views/robots/index.html.erb +106 -0
- data/examples/rails_app/app/views/robots/new.html.erb +36 -0
- data/examples/rails_app/app/views/robots/show.html.erb +79 -0
- data/examples/rails_app/app/views/search/index.html.erb +184 -0
- data/examples/rails_app/app/views/shared/_navbar.html.erb +52 -0
- data/examples/rails_app/app/views/shared/_stat_card.html.erb +52 -0
- data/examples/rails_app/app/views/tags/index.html.erb +131 -0
- data/examples/rails_app/app/views/tags/show.html.erb +67 -0
- data/examples/rails_app/bin/dev +8 -0
- data/examples/rails_app/bin/rails +4 -0
- data/examples/rails_app/bin/rake +4 -0
- data/examples/rails_app/config/application.rb +33 -0
- data/examples/rails_app/config/boot.rb +5 -0
- data/examples/rails_app/config/database.yml +15 -0
- data/examples/rails_app/config/environment.rb +5 -0
- data/examples/rails_app/config/importmap.rb +7 -0
- data/examples/rails_app/config/routes.rb +38 -0
- data/examples/rails_app/config/tailwind.config.js +35 -0
- data/examples/rails_app/config.ru +5 -0
- data/examples/rails_app/log/.keep +0 -0
- data/examples/rails_app/tmp/local_secret.txt +1 -0
- data/examples/robot_groups/multi_process.rb +5 -5
- data/examples/robot_groups/robot_worker.rb +5 -5
- data/examples/robot_groups/same_process.rb +9 -9
- data/examples/sinatra_app/app.rb +1 -1
- data/examples/timeframe_demo.rb +1 -1
- data/lib/htm/active_record_config.rb +12 -28
- data/lib/htm/circuit_breaker.rb +0 -2
- data/lib/htm/config/defaults.yml +246 -0
- data/lib/htm/config.rb +888 -0
- data/lib/htm/database.rb +26 -33
- data/lib/htm/embedding_service.rb +0 -4
- data/lib/htm/integrations/sinatra.rb +3 -7
- data/lib/htm/job_adapter.rb +1 -15
- data/lib/htm/jobs/generate_embedding_job.rb +1 -7
- data/lib/htm/jobs/generate_propositions_job.rb +2 -12
- data/lib/htm/jobs/generate_tags_job.rb +1 -8
- data/lib/htm/loaders/defaults_loader.rb +143 -0
- data/lib/htm/loaders/xdg_config_loader.rb +116 -0
- data/lib/htm/mcp/cli.rb +475 -0
- data/lib/htm/mcp/group_tools.rb +476 -0
- data/lib/htm/mcp/resources.rb +89 -0
- data/lib/htm/mcp/server.rb +98 -0
- data/lib/htm/mcp/tools.rb +488 -0
- data/lib/htm/models/file_source.rb +5 -3
- data/lib/htm/proposition_service.rb +2 -12
- data/lib/htm/railtie.rb +3 -8
- data/lib/htm/tag_service.rb +1 -8
- data/lib/htm/tasks.rb +7 -4
- data/lib/htm/version.rb +1 -1
- data/lib/htm.rb +124 -5
- data/lib/tasks/htm.rake +6 -9
- metadata +81 -6
- data/bin/htm_mcp.rb +0 -621
- data/config/database.yml +0 -74
- data/lib/htm/configuration.rb +0 -766
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
<div class="space-y-6">
|
|
2
|
+
<!-- Header -->
|
|
3
|
+
<div class="flex items-center justify-between">
|
|
4
|
+
<div>
|
|
5
|
+
<h1 class="text-2xl font-bold text-white">Tags</h1>
|
|
6
|
+
<p class="mt-1 text-sm text-gray-400">Hierarchical tag organization</p>
|
|
7
|
+
</div>
|
|
8
|
+
<div class="flex items-center gap-2 rounded-lg bg-gray-800 border border-gray-700 p-1">
|
|
9
|
+
<%= link_to tags_path(view: 'list'), class: "rounded px-3 py-1.5 text-sm font-medium #{@view_type == 'list' ? 'bg-indigo-600 text-white' : 'text-gray-400 hover:text-white'}" do %>
|
|
10
|
+
List
|
|
11
|
+
<% end %>
|
|
12
|
+
<%= link_to tags_path(view: 'tree'), class: "rounded px-3 py-1.5 text-sm font-medium #{@view_type == 'tree' ? 'bg-indigo-600 text-white' : 'text-gray-400 hover:text-white'}" do %>
|
|
13
|
+
Tree
|
|
14
|
+
<% end %>
|
|
15
|
+
<%= link_to tags_path(view: 'mermaid'), class: "rounded px-3 py-1.5 text-sm font-medium #{@view_type == 'mermaid' ? 'bg-indigo-600 text-white' : 'text-gray-400 hover:text-white'}" do %>
|
|
16
|
+
Diagram
|
|
17
|
+
<% end %>
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
<% case @view_type %>
|
|
22
|
+
<% when 'tree' %>
|
|
23
|
+
<!-- Tree View -->
|
|
24
|
+
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
25
|
+
<!-- Text Tree -->
|
|
26
|
+
<div class="rounded-lg bg-gray-800 border border-gray-700 p-6">
|
|
27
|
+
<h2 class="text-lg font-medium text-white mb-4">Text Tree</h2>
|
|
28
|
+
<% if @tree_string.present? %>
|
|
29
|
+
<pre class="text-sm text-gray-300 font-mono overflow-x-auto"><%= @tree_string %></pre>
|
|
30
|
+
<% else %>
|
|
31
|
+
<p class="text-sm text-gray-500">No tags to display.</p>
|
|
32
|
+
<% end %>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<!-- SVG Visualization -->
|
|
36
|
+
<div class="rounded-lg bg-gray-800 border border-gray-700 p-6">
|
|
37
|
+
<h2 class="text-lg font-medium text-white mb-4">Visual Hierarchy</h2>
|
|
38
|
+
<% if @tree_svg.present? %>
|
|
39
|
+
<div class="overflow-x-auto">
|
|
40
|
+
<%= raw @tree_svg %>
|
|
41
|
+
</div>
|
|
42
|
+
<% else %>
|
|
43
|
+
<p class="text-sm text-gray-500">No tags to display.</p>
|
|
44
|
+
<% end %>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<% when 'mermaid' %>
|
|
49
|
+
<!-- Mermaid Diagram -->
|
|
50
|
+
<div class="rounded-lg bg-gray-800 border border-gray-700 p-6">
|
|
51
|
+
<h2 class="text-lg font-medium text-white mb-4">Mermaid Diagram</h2>
|
|
52
|
+
<% if @tree_mermaid.present? %>
|
|
53
|
+
<div class="rounded-md bg-gray-900 p-4 overflow-x-auto">
|
|
54
|
+
<pre class="text-sm text-gray-300 font-mono"><%= @tree_mermaid %></pre>
|
|
55
|
+
</div>
|
|
56
|
+
<p class="mt-4 text-xs text-gray-500">Copy this code to render in any Mermaid-compatible viewer.</p>
|
|
57
|
+
<% else %>
|
|
58
|
+
<p class="text-sm text-gray-500">No tags to display.</p>
|
|
59
|
+
<% end %>
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<% else %>
|
|
63
|
+
<!-- List View -->
|
|
64
|
+
<div class="rounded-lg bg-gray-800 border border-gray-700 p-4">
|
|
65
|
+
<%= form_with url: tags_path, method: :get, class: 'flex gap-4' do %>
|
|
66
|
+
<div class="flex-1">
|
|
67
|
+
<%= text_field_tag :prefix, params[:prefix], placeholder: 'Filter by prefix (e.g., database)', class: 'w-full rounded-md bg-gray-700 border-gray-600 text-white placeholder-gray-400 text-sm focus:ring-indigo-500 focus:border-indigo-500' %>
|
|
68
|
+
</div>
|
|
69
|
+
<%= submit_tag 'Filter', class: 'rounded-md bg-indigo-600 px-4 py-2 text-sm font-medium text-white hover:bg-indigo-500 cursor-pointer' %>
|
|
70
|
+
<% if params[:prefix].present? %>
|
|
71
|
+
<%= link_to 'Clear', tags_path, class: 'rounded-md bg-gray-700 px-4 py-2 text-sm font-medium text-white hover:bg-gray-600' %>
|
|
72
|
+
<% end %>
|
|
73
|
+
<% end %>
|
|
74
|
+
</div>
|
|
75
|
+
|
|
76
|
+
<% if @tags.any? %>
|
|
77
|
+
<div class="rounded-lg bg-gray-800 border border-gray-700 overflow-hidden">
|
|
78
|
+
<table class="min-w-full divide-y divide-gray-700">
|
|
79
|
+
<thead class="bg-gray-800/50">
|
|
80
|
+
<tr>
|
|
81
|
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Tag</th>
|
|
82
|
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Hierarchy</th>
|
|
83
|
+
<th scope="col" class="px-6 py-3 text-left text-xs font-medium text-gray-400 uppercase tracking-wider">Memories</th>
|
|
84
|
+
<th scope="col" class="relative px-6 py-3"><span class="sr-only">Actions</span></th>
|
|
85
|
+
</tr>
|
|
86
|
+
</thead>
|
|
87
|
+
<tbody class="divide-y divide-gray-700">
|
|
88
|
+
<% @tags.each do |tag| %>
|
|
89
|
+
<tr class="hover:bg-gray-700/50 transition-colors">
|
|
90
|
+
<td class="px-6 py-4 whitespace-nowrap">
|
|
91
|
+
<%= link_to tag_path(tag), class: 'inline-flex items-center rounded-full bg-indigo-900/50 border border-indigo-500/30 px-3 py-1 text-sm text-indigo-300 hover:bg-indigo-800/50 transition-colors' do %>
|
|
92
|
+
<%= tag.name %>
|
|
93
|
+
<% end %>
|
|
94
|
+
</td>
|
|
95
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-400">
|
|
96
|
+
<% parts = tag.name.split(':') %>
|
|
97
|
+
<% parts.each_with_index do |part, i| %>
|
|
98
|
+
<% if i > 0 %><span class="text-gray-600 mx-1">/</span><% end %>
|
|
99
|
+
<span class="<%= i == parts.length - 1 ? 'text-white' : 'text-gray-500' %>"><%= part %></span>
|
|
100
|
+
<% end %>
|
|
101
|
+
</td>
|
|
102
|
+
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-400">
|
|
103
|
+
<%= tag.node_count %>
|
|
104
|
+
</td>
|
|
105
|
+
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
|
106
|
+
<%= link_to 'View', tag_path(tag), class: 'text-indigo-400 hover:text-indigo-300' %>
|
|
107
|
+
<span class="mx-2 text-gray-600">|</span>
|
|
108
|
+
<%= link_to 'Filter Memories', memories_path(tag: tag.name), class: 'text-indigo-400 hover:text-indigo-300' %>
|
|
109
|
+
</td>
|
|
110
|
+
</tr>
|
|
111
|
+
<% end %>
|
|
112
|
+
</tbody>
|
|
113
|
+
</table>
|
|
114
|
+
</div>
|
|
115
|
+
<% else %>
|
|
116
|
+
<div class="rounded-lg bg-gray-800 border border-gray-700 p-8 text-center">
|
|
117
|
+
<svg class="mx-auto h-12 w-12 text-gray-500" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
118
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
|
|
119
|
+
</svg>
|
|
120
|
+
<h3 class="mt-4 text-lg font-medium text-white">No tags found</h3>
|
|
121
|
+
<p class="mt-2 text-sm text-gray-400">
|
|
122
|
+
<% if params[:prefix].present? %>
|
|
123
|
+
No tags match that prefix. <%= link_to 'Clear filter', tags_path, class: 'text-indigo-400 hover:text-indigo-300' %>.
|
|
124
|
+
<% else %>
|
|
125
|
+
Tags are automatically generated when you add memories.
|
|
126
|
+
<% end %>
|
|
127
|
+
</p>
|
|
128
|
+
</div>
|
|
129
|
+
<% end %>
|
|
130
|
+
<% end %>
|
|
131
|
+
</div>
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<div class="space-y-6">
|
|
2
|
+
<!-- Back link -->
|
|
3
|
+
<div>
|
|
4
|
+
<%= link_to tags_path, class: 'inline-flex items-center gap-1 text-sm text-gray-400 hover:text-white transition-colors' do %>
|
|
5
|
+
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
6
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 19l-7-7m0 0l7-7m-7 7h18" />
|
|
7
|
+
</svg>
|
|
8
|
+
Back to Tags
|
|
9
|
+
<% end %>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
<!-- Tag Header -->
|
|
13
|
+
<div class="rounded-lg bg-gray-800 border border-gray-700 p-6">
|
|
14
|
+
<div class="flex items-start justify-between">
|
|
15
|
+
<div>
|
|
16
|
+
<div class="flex items-center gap-3">
|
|
17
|
+
<div class="rounded-full bg-indigo-900/50 border border-indigo-500/30 p-2">
|
|
18
|
+
<svg class="h-5 w-5 text-indigo-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
19
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 7h.01M7 3h5c.512 0 1.024.195 1.414.586l7 7a2 2 0 010 2.828l-7 7a2 2 0 01-2.828 0l-7-7A1.994 1.994 0 013 12V7a4 4 0 014-4z" />
|
|
20
|
+
</svg>
|
|
21
|
+
</div>
|
|
22
|
+
<h1 class="text-2xl font-bold text-white"><%= @tag.name %></h1>
|
|
23
|
+
</div>
|
|
24
|
+
|
|
25
|
+
<!-- Hierarchy breadcrumb -->
|
|
26
|
+
<div class="mt-3 flex items-center gap-1 text-sm">
|
|
27
|
+
<% parts = @tag.name.split(':') %>
|
|
28
|
+
<% parts.each_with_index do |part, i| %>
|
|
29
|
+
<% if i > 0 %>
|
|
30
|
+
<svg class="h-4 w-4 text-gray-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
31
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
|
32
|
+
</svg>
|
|
33
|
+
<% end %>
|
|
34
|
+
<% prefix = parts[0..i].join(':') %>
|
|
35
|
+
<% matching_tag = HTM::Models::Tag.find_by(name: prefix) %>
|
|
36
|
+
<% if matching_tag %>
|
|
37
|
+
<%= link_to part, tag_path(matching_tag), class: "#{i == parts.length - 1 ? 'text-indigo-400' : 'text-gray-400 hover:text-white'}" %>
|
|
38
|
+
<% else %>
|
|
39
|
+
<span class="text-gray-500"><%= part %></span>
|
|
40
|
+
<% end %>
|
|
41
|
+
<% end %>
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<div class="text-right">
|
|
46
|
+
<p class="text-2xl font-bold text-white"><%= @memories.count %></p>
|
|
47
|
+
<p class="text-sm text-gray-400">memories</p>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<!-- Memories with this tag -->
|
|
53
|
+
<div>
|
|
54
|
+
<h2 class="text-lg font-medium text-white mb-4">Memories with this tag</h2>
|
|
55
|
+
<% if @memories.any? %>
|
|
56
|
+
<div class="space-y-4">
|
|
57
|
+
<% @memories.each do |memory| %>
|
|
58
|
+
<%= render 'memories/memory_card', memory: memory %>
|
|
59
|
+
<% end %>
|
|
60
|
+
</div>
|
|
61
|
+
<% else %>
|
|
62
|
+
<div class="rounded-lg bg-gray-800 border border-gray-700 p-8 text-center">
|
|
63
|
+
<p class="text-sm text-gray-500">No memories with this tag.</p>
|
|
64
|
+
</div>
|
|
65
|
+
<% end %>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'boot'
|
|
4
|
+
|
|
5
|
+
require 'rails'
|
|
6
|
+
require 'active_model/railtie'
|
|
7
|
+
require 'active_job/railtie'
|
|
8
|
+
require 'active_record/railtie'
|
|
9
|
+
require 'action_controller/railtie'
|
|
10
|
+
require 'action_view/railtie'
|
|
11
|
+
|
|
12
|
+
# Require HTM - this will auto-load the Railtie
|
|
13
|
+
require 'htm'
|
|
14
|
+
|
|
15
|
+
module HtmRailsExample
|
|
16
|
+
class Application < Rails::Application
|
|
17
|
+
config.load_defaults 7.1
|
|
18
|
+
|
|
19
|
+
# Full-stack Rails app (not API-only)
|
|
20
|
+
config.api_only = false
|
|
21
|
+
|
|
22
|
+
# Use inline jobs for simplicity in demo
|
|
23
|
+
config.active_job.queue_adapter = :inline
|
|
24
|
+
|
|
25
|
+
# Generators config
|
|
26
|
+
config.generators do |g|
|
|
27
|
+
g.test_framework nil
|
|
28
|
+
g.stylesheets false
|
|
29
|
+
g.javascripts false
|
|
30
|
+
g.helper false
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Rails app database (not used - HTM uses its own database)
|
|
2
|
+
# This is required for Rails to boot but can be sqlite/memory
|
|
3
|
+
|
|
4
|
+
default: &default
|
|
5
|
+
adapter: postgresql
|
|
6
|
+
encoding: unicode
|
|
7
|
+
pool: 5
|
|
8
|
+
|
|
9
|
+
development:
|
|
10
|
+
<<: *default
|
|
11
|
+
database: htm_rails_example_dev
|
|
12
|
+
|
|
13
|
+
test:
|
|
14
|
+
<<: *default
|
|
15
|
+
database: htm_rails_example_test
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
pin "application"
|
|
4
|
+
pin "@hotwired/turbo-rails", to: "turbo.min.js"
|
|
5
|
+
pin "@hotwired/stimulus", to: "stimulus.min.js"
|
|
6
|
+
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
|
|
7
|
+
pin_all_from "app/javascript/controllers", under: "controllers"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Rails.application.routes.draw do
|
|
4
|
+
root 'dashboard#index'
|
|
5
|
+
|
|
6
|
+
resources :memories do
|
|
7
|
+
collection do
|
|
8
|
+
get :deleted
|
|
9
|
+
end
|
|
10
|
+
member do
|
|
11
|
+
post :restore
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
resources :tags, only: [:index, :show]
|
|
16
|
+
|
|
17
|
+
resources :robots, only: [:index, :show, :new, :create] do
|
|
18
|
+
member do
|
|
19
|
+
post :switch
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
resource :search, only: [:index], controller: 'search' do
|
|
24
|
+
get '/', action: :index
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
resources :files, only: [:index, :show, :new, :create, :destroy] do
|
|
28
|
+
collection do
|
|
29
|
+
post :load_directory
|
|
30
|
+
post :upload
|
|
31
|
+
post :upload_directory
|
|
32
|
+
post :sync_all
|
|
33
|
+
end
|
|
34
|
+
member do
|
|
35
|
+
post :sync
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const defaultTheme = require('tailwindcss/defaultTheme')
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
darkMode: 'class',
|
|
5
|
+
content: [
|
|
6
|
+
'./app/views/**/*.html.erb',
|
|
7
|
+
'./app/helpers/**/*.rb',
|
|
8
|
+
'./app/javascript/**/*.js',
|
|
9
|
+
'./app/assets/stylesheets/**/*.css',
|
|
10
|
+
],
|
|
11
|
+
theme: {
|
|
12
|
+
extend: {
|
|
13
|
+
fontFamily: {
|
|
14
|
+
sans: ['Inter', ...defaultTheme.fontFamily.sans],
|
|
15
|
+
mono: ['JetBrains Mono', ...defaultTheme.fontFamily.mono],
|
|
16
|
+
},
|
|
17
|
+
colors: {
|
|
18
|
+
htm: {
|
|
19
|
+
50: '#f0f9ff',
|
|
20
|
+
100: '#e0f2fe',
|
|
21
|
+
200: '#bae6fd',
|
|
22
|
+
300: '#7dd3fc',
|
|
23
|
+
400: '#38bdf8',
|
|
24
|
+
500: '#0ea5e9',
|
|
25
|
+
600: '#0284c7',
|
|
26
|
+
700: '#0369a1',
|
|
27
|
+
800: '#075985',
|
|
28
|
+
900: '#0c4a6e',
|
|
29
|
+
950: '#082f49',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
plugins: [],
|
|
35
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
8ec864777deb2e477c24acfa26c5a4721c6d36f04e80b9ecb00d22002a591a12d213fd8e4d2107471e65de7f546f2a1e27317d1ea2c0130dc19e39f36af610a9
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# 4. Dynamic scaling by spawning new processes
|
|
14
14
|
#
|
|
15
15
|
# Prerequisites:
|
|
16
|
-
# 1. Set
|
|
16
|
+
# 1. Set HTM_DATABASE__URL environment variable
|
|
17
17
|
# 2. Initialize database schema: rake db_setup
|
|
18
18
|
|
|
19
19
|
require_relative '../../lib/htm'
|
|
@@ -36,7 +36,7 @@ class RobotProcess
|
|
|
36
36
|
|
|
37
37
|
# Spawn the worker process
|
|
38
38
|
@stdin, @stdout, @stderr, @wait_thread = Open3.popen3(
|
|
39
|
-
{ '
|
|
39
|
+
{ 'HTM_DATABASE__URL' => ENV['HTM_DATABASE__URL'] },
|
|
40
40
|
'ruby', WORKER_SCRIPT, name, group_name
|
|
41
41
|
)
|
|
42
42
|
@pid = @wait_thread.pid
|
|
@@ -119,9 +119,9 @@ def run_demo
|
|
|
119
119
|
|
|
120
120
|
BANNER
|
|
121
121
|
|
|
122
|
-
unless ENV['
|
|
123
|
-
puts 'ERROR:
|
|
124
|
-
puts ' export
|
|
122
|
+
unless ENV['HTM_DATABASE__URL']
|
|
123
|
+
puts 'ERROR: HTM_DATABASE__URL not set.'
|
|
124
|
+
puts ' export HTM_DATABASE__URL="postgresql://user@localhost:5432/htm_development"'
|
|
125
125
|
exit 1
|
|
126
126
|
end
|
|
127
127
|
|
|
@@ -37,11 +37,11 @@ end
|
|
|
37
37
|
|
|
38
38
|
# Configure HTM with logger to stderr (keep stdout clean for JSON)
|
|
39
39
|
HTM.configure do |config|
|
|
40
|
-
config.
|
|
41
|
-
config.
|
|
42
|
-
config.
|
|
43
|
-
config.
|
|
44
|
-
config.
|
|
40
|
+
config.embedding.provider = :ollama
|
|
41
|
+
config.embedding.model = 'nomic-embed-text:latest'
|
|
42
|
+
config.embedding.dimensions = 768
|
|
43
|
+
config.tag.provider = :ollama
|
|
44
|
+
config.tag.model = 'gemma3:latest'
|
|
45
45
|
config.logger = Logger.new($stderr, level: Logger::WARN)
|
|
46
46
|
end
|
|
47
47
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
# synchronization of in-memory working memory across robots.
|
|
20
20
|
#
|
|
21
21
|
# Prerequisites:
|
|
22
|
-
# 1. Set
|
|
22
|
+
# 1. Set HTM_DATABASE__URL environment variable
|
|
23
23
|
# 2. Initialize database schema: rake db_setup
|
|
24
24
|
# 3. Install dependencies: bundle install
|
|
25
25
|
|
|
@@ -33,9 +33,9 @@ require 'json'
|
|
|
33
33
|
puts 'HTM Robot Group Demo - Shared Working Memory & Failover'
|
|
34
34
|
puts '=' * 60
|
|
35
35
|
|
|
36
|
-
unless ENV['
|
|
37
|
-
puts 'ERROR:
|
|
38
|
-
puts ' export
|
|
36
|
+
unless ENV['HTM_DATABASE__URL']
|
|
37
|
+
puts 'ERROR: HTM_DATABASE__URL not set. Please set it:'
|
|
38
|
+
puts ' export HTM_DATABASE__URL="postgresql://postgres@localhost:5432/htm_development"'
|
|
39
39
|
exit 1
|
|
40
40
|
end
|
|
41
41
|
|
|
@@ -43,11 +43,11 @@ begin
|
|
|
43
43
|
# Configure HTM
|
|
44
44
|
puts "\n1. Configuring HTM..."
|
|
45
45
|
HTM.configure do |config|
|
|
46
|
-
config.
|
|
47
|
-
config.
|
|
48
|
-
config.
|
|
49
|
-
config.
|
|
50
|
-
config.
|
|
46
|
+
config.embedding.provider = :ollama
|
|
47
|
+
config.embedding.model = 'nomic-embed-text:latest'
|
|
48
|
+
config.embedding.dimensions = 768
|
|
49
|
+
config.tag.provider = :ollama
|
|
50
|
+
config.tag.model = 'gemma3:latest'
|
|
51
51
|
end
|
|
52
52
|
puts '✓ HTM configured'
|
|
53
53
|
|
data/examples/sinatra_app/app.rb
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
# bundle exec ruby app.rb
|
|
15
15
|
#
|
|
16
16
|
# Environment:
|
|
17
|
-
#
|
|
17
|
+
# HTM_DATABASE__URL - PostgreSQL connection URL (required)
|
|
18
18
|
# REDIS_URL - Redis connection URL (for Sidekiq, default: redis://localhost:6379/0)
|
|
19
19
|
# OLLAMA_URL - Ollama server URL (default: http://localhost:11434)
|
|
20
20
|
#
|
data/examples/timeframe_demo.rb
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# Timeframe Demo - Demonstrates the various ways to use timeframes with recall
|
|
5
5
|
#
|
|
6
6
|
# Run with:
|
|
7
|
-
#
|
|
7
|
+
# HTM_DATABASE__URL="postgresql://localhost/htm_development" ruby examples/timeframe_demo.rb
|
|
8
8
|
|
|
9
9
|
require_relative "../lib/htm"
|
|
10
10
|
|
|
@@ -3,14 +3,17 @@
|
|
|
3
3
|
require 'active_record'
|
|
4
4
|
require 'pg'
|
|
5
5
|
require 'neighbor'
|
|
6
|
-
require 'erb'
|
|
7
|
-
require 'yaml'
|
|
8
6
|
|
|
9
7
|
class HTM
|
|
10
8
|
# ActiveRecord database configuration and model loading
|
|
9
|
+
#
|
|
10
|
+
# Uses HTM::Config for database settings. Configuration can come from:
|
|
11
|
+
# - Environment variables (HTM_DATABASE__URL, HTM_DATABASE__HOST, etc.)
|
|
12
|
+
# - Programmatic configuration via HTM.configure
|
|
13
|
+
#
|
|
11
14
|
class ActiveRecordConfig
|
|
12
15
|
class << self
|
|
13
|
-
# Establish database connection from
|
|
16
|
+
# Establish database connection from HTM::Config
|
|
14
17
|
def establish_connection!
|
|
15
18
|
config = load_database_config
|
|
16
19
|
|
|
@@ -25,30 +28,12 @@ class HTM
|
|
|
25
28
|
true
|
|
26
29
|
end
|
|
27
30
|
|
|
28
|
-
# Load
|
|
31
|
+
# Load database configuration from HTM::Config
|
|
32
|
+
#
|
|
33
|
+
# @return [Hash] ActiveRecord-compatible configuration hash
|
|
34
|
+
#
|
|
29
35
|
def load_database_config
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
unless File.exist?(config_path)
|
|
33
|
-
raise "Database configuration file not found at #{config_path}"
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Read and parse ERB
|
|
37
|
-
erb_content = ERB.new(File.read(config_path)).result
|
|
38
|
-
db_config = YAML.safe_load(erb_content, aliases: true)
|
|
39
|
-
|
|
40
|
-
# Determine environment
|
|
41
|
-
env = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
|
|
42
|
-
|
|
43
|
-
# Get configuration for current environment
|
|
44
|
-
config = db_config[env]
|
|
45
|
-
|
|
46
|
-
unless config
|
|
47
|
-
raise "No database configuration found for environment: #{env}"
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# Convert string keys to symbols for ActiveRecord
|
|
51
|
-
config.transform_keys(&:to_sym)
|
|
36
|
+
HTM.config.database_config
|
|
52
37
|
end
|
|
53
38
|
|
|
54
39
|
# Check if connection is established and active
|
|
@@ -59,8 +44,7 @@ class HTM
|
|
|
59
44
|
ActiveRecord::Base.connected? && ActiveRecord::Base.connection.active?
|
|
60
45
|
rescue ActiveRecord::ConnectionNotDefined, ActiveRecord::ConnectionNotEstablished
|
|
61
46
|
false
|
|
62
|
-
rescue StandardError
|
|
63
|
-
HTM.logger.debug "Connection check failed: #{e.class} - #{e.message}"
|
|
47
|
+
rescue StandardError
|
|
64
48
|
false
|
|
65
49
|
end
|
|
66
50
|
|
data/lib/htm/circuit_breaker.rb
CHANGED
|
@@ -73,8 +73,6 @@ class HTM
|
|
|
73
73
|
HTM.logger.warn "CircuitBreaker[#{@name}]: Circuit is OPEN, failing fast"
|
|
74
74
|
raise CircuitBreakerOpenError, "Circuit breaker '#{@name}' is open. Service unavailable."
|
|
75
75
|
end
|
|
76
|
-
when :half_open
|
|
77
|
-
HTM.logger.debug "CircuitBreaker[#{@name}]: Circuit is HALF-OPEN, testing service"
|
|
78
76
|
end
|
|
79
77
|
end
|
|
80
78
|
|