hermes-local-rag 1.3.1__tar.gz
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.
- hermes_local_rag-1.3.1/.github/workflows/ci.yml +21 -0
- hermes_local_rag-1.3.1/.github/workflows/publish-pypi.yml +28 -0
- hermes_local_rag-1.3.1/.gitignore +19 -0
- hermes_local_rag-1.3.1/LICENSE +21 -0
- hermes_local_rag-1.3.1/PKG-INFO +123 -0
- hermes_local_rag-1.3.1/README.md +100 -0
- hermes_local_rag-1.3.1/assets/branding/local-rag-icon-transparent.png +0 -0
- hermes_local_rag-1.3.1/assets/branding/local-rag-icon-transparent.webp +0 -0
- hermes_local_rag-1.3.1/assets/branding/local-rag-icon.jpg +0 -0
- hermes_local_rag-1.3.1/assets/branding/local-rag-icon.png +0 -0
- hermes_local_rag-1.3.1/assets/branding/local-rag-icon.webp +0 -0
- hermes_local_rag-1.3.1/assets/branding/local-rag-mark.svg +36 -0
- hermes_local_rag-1.3.1/assets/branding/local-rag-preview-1600x900.jpg +0 -0
- hermes_local_rag-1.3.1/assets/branding/local-rag-preview-1600x900.png +0 -0
- hermes_local_rag-1.3.1/assets/branding/local-rag-preview-1600x900.webp +0 -0
- hermes_local_rag-1.3.1/assets/branding/local-rag-social-1280x640.jpg +0 -0
- hermes_local_rag-1.3.1/assets/branding/local-rag-social-1280x640.png +0 -0
- hermes_local_rag-1.3.1/assets/branding/local-rag-social-1280x640.webp +0 -0
- hermes_local_rag-1.3.1/conftest.py +24 -0
- hermes_local_rag-1.3.1/install.py +97 -0
- hermes_local_rag-1.3.1/local_rag/README.md +57 -0
- hermes_local_rag-1.3.1/local_rag/__init__.py +333 -0
- hermes_local_rag-1.3.1/local_rag/backfill.py +426 -0
- hermes_local_rag-1.3.1/local_rag/chunking.py +25 -0
- hermes_local_rag-1.3.1/local_rag/cli.py +236 -0
- hermes_local_rag-1.3.1/local_rag/config.py +99 -0
- hermes_local_rag-1.3.1/local_rag/dashboard/__init__.py +1 -0
- hermes_local_rag-1.3.1/local_rag/dashboard/dist/index.js +301 -0
- hermes_local_rag-1.3.1/local_rag/dashboard/dist/style.css +51 -0
- hermes_local_rag-1.3.1/local_rag/dashboard/manifest.json +14 -0
- hermes_local_rag-1.3.1/local_rag/dashboard/plugin_api.py +503 -0
- hermes_local_rag-1.3.1/local_rag/dashboard/src/index.js +301 -0
- hermes_local_rag-1.3.1/local_rag/dashboard/src/style.css +51 -0
- hermes_local_rag-1.3.1/local_rag/embedder.py +60 -0
- hermes_local_rag-1.3.1/local_rag/extraction.py +47 -0
- hermes_local_rag-1.3.1/local_rag/plugin.yaml +5 -0
- hermes_local_rag-1.3.1/local_rag/policy.py +34 -0
- hermes_local_rag-1.3.1/local_rag/service.py +80 -0
- hermes_local_rag-1.3.1/local_rag/sessions.py +12 -0
- hermes_local_rag-1.3.1/local_rag/store.py +321 -0
- hermes_local_rag-1.3.1/local_rag/tests/test_dashboard_api.py +346 -0
- hermes_local_rag-1.3.1/local_rag/tests/test_full.py +507 -0
- hermes_local_rag-1.3.1/local_rag/tests/test_local_rag.py +497 -0
- hermes_local_rag-1.3.1/local_rag/visual.py +62 -0
- hermes_local_rag-1.3.1/local_rag/visual_store.py +86 -0
- hermes_local_rag-1.3.1/pyproject.toml +48 -0
- hermes_local_rag-1.3.1/uv.lock +1078 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
name: ci
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
test:
|
|
12
|
+
runs-on: macos-14
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: astral-sh/setup-uv@v6
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.11"
|
|
19
|
+
- run: uv sync --all-groups
|
|
20
|
+
- run: uv run pytest
|
|
21
|
+
- run: uv build
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
name: publish-pypi
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
publish:
|
|
13
|
+
name: Build and publish to PyPI
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
environment:
|
|
16
|
+
name: pypi
|
|
17
|
+
url: https://pypi.org/project/hermes-local-rag/
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
id-token: write
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4
|
|
23
|
+
- uses: astral-sh/setup-uv@d0d8abe699bfb85fec6de9f7adb5ae17292296ff # v6
|
|
24
|
+
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: "3.11"
|
|
27
|
+
- run: uv build
|
|
28
|
+
- uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
.pytest_cache/
|
|
4
|
+
.venv/
|
|
5
|
+
dist/
|
|
6
|
+
!local_rag/dashboard/dist/
|
|
7
|
+
!local_rag/dashboard/dist/**
|
|
8
|
+
build/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
.DS_Store
|
|
11
|
+
.coverage
|
|
12
|
+
assets/*.zip
|
|
13
|
+
|
|
14
|
+
# Never commit local memory, models, exports, or credentials
|
|
15
|
+
local-rag/
|
|
16
|
+
models/
|
|
17
|
+
*.sqlite*
|
|
18
|
+
*.jsonl
|
|
19
|
+
.env*
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 condr-at
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: hermes-local-rag
|
|
3
|
+
Version: 1.3.1
|
|
4
|
+
Summary: Private local hybrid text and visual memory provider for Hermes Agent
|
|
5
|
+
Project-URL: Repository, https://github.com/condr-at/hermes-local-rag
|
|
6
|
+
Project-URL: Issues, https://github.com/condr-at/hermes-local-rag/issues
|
|
7
|
+
Author: condr-at
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
14
|
+
Requires-Python: >=3.11
|
|
15
|
+
Requires-Dist: ai-edge-litert<3,>=2.1; platform_system == 'Darwin' or platform_system == 'Linux'
|
|
16
|
+
Requires-Dist: huggingface-hub<2,>=0.34
|
|
17
|
+
Requires-Dist: jsonschema<5,>=4
|
|
18
|
+
Requires-Dist: numpy<3,>=2.0
|
|
19
|
+
Requires-Dist: onnxruntime<2,>=1.20
|
|
20
|
+
Requires-Dist: pillow<13,>=11
|
|
21
|
+
Requires-Dist: tokenizers<1,>=0.22
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# Hermes Local RAG
|
|
25
|
+
|
|
26
|
+
[](https://github.com/condr-at/hermes-local-rag)
|
|
27
|
+
|
|
28
|
+
Private, fully local hybrid text and visual memory for [Hermes Agent](https://github.com/NousResearch/hermes-agent), implemented through the official `MemoryProvider` extension point.
|
|
29
|
+
|
|
30
|
+
## Features
|
|
31
|
+
|
|
32
|
+
- EmbeddingGemma 300M through LiteRT/XNNPACK, with configurable 128/256/512/768-dimensional Matryoshka embeddings (512d default)
|
|
33
|
+
- SQLite + FTS5 + vector similarity, score thresholds, freshness/importance boosts, source diversity, and bounded context injection
|
|
34
|
+
- Physical profile/user namespaces before retrieval
|
|
35
|
+
- Explicit contextual admission through `local_rag_remember`, with normalized atomic items instead of raw turns
|
|
36
|
+
- Selective historical backfill with pre-LLM filtering, structured extraction, resumable preview, human review, and explicit apply
|
|
37
|
+
- Independent scope, durability, status, confidence, importance, provenance, deduplication, deletion, migrations, and backups
|
|
38
|
+
- Project- and session-aware retrieval boundaries; built-in Markdown memory is mirrored as global durable context
|
|
39
|
+
- Project-root-confined text-file indexing with secret and prompt-injection rejection
|
|
40
|
+
- Optional CLIP ViT-B/32 ONNX visual index in a separate 512d vector space
|
|
41
|
+
- Button-driven setup inside Hermes Dashboard; no model server, vector database server, or Hermes core patch
|
|
42
|
+
|
|
43
|
+
## Install without Terminal
|
|
44
|
+
|
|
45
|
+
Prerequisite: an existing Hermes Agent installation.
|
|
46
|
+
|
|
47
|
+
1. Open **Hermes Dashboard → Plugins → Install**.
|
|
48
|
+
2. Install `condr-at/hermes-local-rag/local_rag`.
|
|
49
|
+
3. Open the new **Local RAG** tab.
|
|
50
|
+
4. Click **Install dependencies**.
|
|
51
|
+
5. Open and accept the required Gemma Terms, create a read-only Hugging Face token, paste it into the password field, and click **Sign in**.
|
|
52
|
+
6. Choose **Text only** or **Text + visual**, then click **Download selected models**.
|
|
53
|
+
7. Optionally create a historical preview, edit and accept individual candidates, then explicitly apply the reviewed subset.
|
|
54
|
+
8. Save the memory settings and click **Activate Local RAG**.
|
|
55
|
+
9. Click **Run health check**.
|
|
56
|
+
|
|
57
|
+
The dashboard never displays or logs the Hugging Face token. Model downloads and setup subprocesses use fixed argument lists and a controlled environment rather than a user shell. Gemma Terms acceptance is explicit and cannot be bypassed by the installer.
|
|
58
|
+
|
|
59
|
+
The setup wizard:
|
|
60
|
+
|
|
61
|
+
1. installs pinned runtime dependencies into the Hermes venv;
|
|
62
|
+
2. downloads selected model artifacts to `$HERMES_HOME/models`;
|
|
63
|
+
3. writes configuration atomically;
|
|
64
|
+
4. activates `memory.provider=local_rag`;
|
|
65
|
+
5. checks runtime imports, models, the database, and provider availability.
|
|
66
|
+
|
|
67
|
+
It never deletes `$HERMES_HOME/local-rag`, where indexes and configuration live. Backfill is off by default and requires explicit confirmation.
|
|
68
|
+
|
|
69
|
+
### Terminal fallback
|
|
70
|
+
|
|
71
|
+
The technical installer remains available for development and recovery:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
git clone https://github.com/condr-at/hermes-local-rag.git
|
|
75
|
+
cd hermes-local-rag
|
|
76
|
+
python3 install.py
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Verify after installation or a Hermes update:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
python3 install.py --check
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Then restart the gateway, or start a new Desktop session.
|
|
86
|
+
|
|
87
|
+
## Configuration
|
|
88
|
+
|
|
89
|
+
`~/.hermes/local-rag/config.json`:
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"embedding_dimensions": 512,
|
|
94
|
+
"episodic_ttl_days": null,
|
|
95
|
+
"summary_ttl_days": null
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`null` means infinite retention. Changing `embedding_dimensions` requires explicit reindexing; startup fails loudly rather than mixing incompatible vectors.
|
|
100
|
+
|
|
101
|
+
## Backfill
|
|
102
|
+
|
|
103
|
+
Raw transcript backfill is disabled. Historical sessions pass through role filtering, credential and prompt-injection rejection, bounded structured extraction, and strict validation. Preview writes only a mode-`0600` review artifact; every candidate starts rejected, and only explicitly accepted items can be applied. Namespace, project, session, timestamps, and source-message provenance come from the trusted export rather than the model.
|
|
104
|
+
|
|
105
|
+
The Dashboard owns the normal preview → edit/accept → apply flow. The equivalent recovery CLI is:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
hermes local_rag preview --plan /path/to/review.json
|
|
109
|
+
# Edit only accepted flags/text after reviewing the artifact.
|
|
110
|
+
hermes local_rag apply --plan /path/to/review.json
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Preview is resumable by session and never writes the memory database. Re-applying a reviewed plan is idempotent through scope-aware exact deduplication.
|
|
114
|
+
|
|
115
|
+
## Maintenance
|
|
116
|
+
|
|
117
|
+
The provider exposes tools for status, search, deletion, candidate review, file/session ingestion, pruning, and visual search. A standalone CLI is also installed as `hermes-local-rag`.
|
|
118
|
+
|
|
119
|
+
See [`local_rag/README.md`](local_rag/README.md) for architecture, policies, tools, and recovery details.
|
|
120
|
+
|
|
121
|
+
## Privacy and licensing
|
|
122
|
+
|
|
123
|
+
No indexed data, model weights, credentials, or session exports belong in this repository. Model weights are downloaded directly from their upstream repositories and retain their own terms. EmbeddingGemma is governed by Gemma Terms. Plugin code is MIT licensed.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# Hermes Local RAG
|
|
2
|
+
|
|
3
|
+
[](https://github.com/condr-at/hermes-local-rag)
|
|
4
|
+
|
|
5
|
+
Private, fully local hybrid text and visual memory for [Hermes Agent](https://github.com/NousResearch/hermes-agent), implemented through the official `MemoryProvider` extension point.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- EmbeddingGemma 300M through LiteRT/XNNPACK, with configurable 128/256/512/768-dimensional Matryoshka embeddings (512d default)
|
|
10
|
+
- SQLite + FTS5 + vector similarity, score thresholds, freshness/importance boosts, source diversity, and bounded context injection
|
|
11
|
+
- Physical profile/user namespaces before retrieval
|
|
12
|
+
- Explicit contextual admission through `local_rag_remember`, with normalized atomic items instead of raw turns
|
|
13
|
+
- Selective historical backfill with pre-LLM filtering, structured extraction, resumable preview, human review, and explicit apply
|
|
14
|
+
- Independent scope, durability, status, confidence, importance, provenance, deduplication, deletion, migrations, and backups
|
|
15
|
+
- Project- and session-aware retrieval boundaries; built-in Markdown memory is mirrored as global durable context
|
|
16
|
+
- Project-root-confined text-file indexing with secret and prompt-injection rejection
|
|
17
|
+
- Optional CLIP ViT-B/32 ONNX visual index in a separate 512d vector space
|
|
18
|
+
- Button-driven setup inside Hermes Dashboard; no model server, vector database server, or Hermes core patch
|
|
19
|
+
|
|
20
|
+
## Install without Terminal
|
|
21
|
+
|
|
22
|
+
Prerequisite: an existing Hermes Agent installation.
|
|
23
|
+
|
|
24
|
+
1. Open **Hermes Dashboard → Plugins → Install**.
|
|
25
|
+
2. Install `condr-at/hermes-local-rag/local_rag`.
|
|
26
|
+
3. Open the new **Local RAG** tab.
|
|
27
|
+
4. Click **Install dependencies**.
|
|
28
|
+
5. Open and accept the required Gemma Terms, create a read-only Hugging Face token, paste it into the password field, and click **Sign in**.
|
|
29
|
+
6. Choose **Text only** or **Text + visual**, then click **Download selected models**.
|
|
30
|
+
7. Optionally create a historical preview, edit and accept individual candidates, then explicitly apply the reviewed subset.
|
|
31
|
+
8. Save the memory settings and click **Activate Local RAG**.
|
|
32
|
+
9. Click **Run health check**.
|
|
33
|
+
|
|
34
|
+
The dashboard never displays or logs the Hugging Face token. Model downloads and setup subprocesses use fixed argument lists and a controlled environment rather than a user shell. Gemma Terms acceptance is explicit and cannot be bypassed by the installer.
|
|
35
|
+
|
|
36
|
+
The setup wizard:
|
|
37
|
+
|
|
38
|
+
1. installs pinned runtime dependencies into the Hermes venv;
|
|
39
|
+
2. downloads selected model artifacts to `$HERMES_HOME/models`;
|
|
40
|
+
3. writes configuration atomically;
|
|
41
|
+
4. activates `memory.provider=local_rag`;
|
|
42
|
+
5. checks runtime imports, models, the database, and provider availability.
|
|
43
|
+
|
|
44
|
+
It never deletes `$HERMES_HOME/local-rag`, where indexes and configuration live. Backfill is off by default and requires explicit confirmation.
|
|
45
|
+
|
|
46
|
+
### Terminal fallback
|
|
47
|
+
|
|
48
|
+
The technical installer remains available for development and recovery:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
git clone https://github.com/condr-at/hermes-local-rag.git
|
|
52
|
+
cd hermes-local-rag
|
|
53
|
+
python3 install.py
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Verify after installation or a Hermes update:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
python3 install.py --check
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Then restart the gateway, or start a new Desktop session.
|
|
63
|
+
|
|
64
|
+
## Configuration
|
|
65
|
+
|
|
66
|
+
`~/.hermes/local-rag/config.json`:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"embedding_dimensions": 512,
|
|
71
|
+
"episodic_ttl_days": null,
|
|
72
|
+
"summary_ttl_days": null
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
`null` means infinite retention. Changing `embedding_dimensions` requires explicit reindexing; startup fails loudly rather than mixing incompatible vectors.
|
|
77
|
+
|
|
78
|
+
## Backfill
|
|
79
|
+
|
|
80
|
+
Raw transcript backfill is disabled. Historical sessions pass through role filtering, credential and prompt-injection rejection, bounded structured extraction, and strict validation. Preview writes only a mode-`0600` review artifact; every candidate starts rejected, and only explicitly accepted items can be applied. Namespace, project, session, timestamps, and source-message provenance come from the trusted export rather than the model.
|
|
81
|
+
|
|
82
|
+
The Dashboard owns the normal preview → edit/accept → apply flow. The equivalent recovery CLI is:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
hermes local_rag preview --plan /path/to/review.json
|
|
86
|
+
# Edit only accepted flags/text after reviewing the artifact.
|
|
87
|
+
hermes local_rag apply --plan /path/to/review.json
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Preview is resumable by session and never writes the memory database. Re-applying a reviewed plan is idempotent through scope-aware exact deduplication.
|
|
91
|
+
|
|
92
|
+
## Maintenance
|
|
93
|
+
|
|
94
|
+
The provider exposes tools for status, search, deletion, candidate review, file/session ingestion, pruning, and visual search. A standalone CLI is also installed as `hermes-local-rag`.
|
|
95
|
+
|
|
96
|
+
See [`local_rag/README.md`](local_rag/README.md) for architecture, policies, tools, and recovery details.
|
|
97
|
+
|
|
98
|
+
## Privacy and licensing
|
|
99
|
+
|
|
100
|
+
No indexed data, model weights, credentials, or session exports belong in this repository. Model weights are downloaded directly from their upstream repositories and retain their own terms. EmbeddingGemma is governed by Gemma Terms. Plugin code is MIT licensed.
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">Local RAG memory drawer</title>
|
|
3
|
+
<desc id="desc">A dark archive drawer holding an ivory memory card, with an amber node mark and a rejected crumpled note.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="body" x1="0" y1="0" x2="1" y2="1">
|
|
6
|
+
<stop offset="0" stop-color="#343330"/>
|
|
7
|
+
<stop offset="1" stop-color="#151615"/>
|
|
8
|
+
</linearGradient>
|
|
9
|
+
<linearGradient id="paper" x1="0" y1="0" x2="0" y2="1">
|
|
10
|
+
<stop offset="0" stop-color="#fff4da"/>
|
|
11
|
+
<stop offset="1" stop-color="#e9d7b5"/>
|
|
12
|
+
</linearGradient>
|
|
13
|
+
<filter id="shadow" x="-30%" y="-30%" width="160%" height="180%">
|
|
14
|
+
<feDropShadow dx="0" dy="18" stdDeviation="18" flood-color="#000" flood-opacity=".28"/>
|
|
15
|
+
</filter>
|
|
16
|
+
</defs>
|
|
17
|
+
<g filter="url(#shadow)">
|
|
18
|
+
<rect x="89" y="78" width="334" height="340" rx="44" fill="url(#body)"/>
|
|
19
|
+
<rect x="119" y="116" width="274" height="224" rx="26" fill="#0e0f0e"/>
|
|
20
|
+
<rect x="139" y="137" width="234" height="170" rx="24" fill="url(#paper)"/>
|
|
21
|
+
<rect x="112" y="249" width="288" height="180" rx="27" fill="url(#body)" stroke="#4a4843" stroke-width="5"/>
|
|
22
|
+
<path d="M112 268h95c10 0 12 28 28 28h42c16 0 18-28 28-28h95v-19H112z" fill="#232321"/>
|
|
23
|
+
<rect x="188" y="334" width="136" height="44" rx="10" fill="#101110" stroke="#535049" stroke-width="5"/>
|
|
24
|
+
<circle cx="256" cy="403" r="17" fill="#252522" stroke="#55524c" stroke-width="4"/>
|
|
25
|
+
</g>
|
|
26
|
+
<g fill="none" stroke="#d98b14" stroke-width="10" stroke-linecap="round" stroke-linejoin="round">
|
|
27
|
+
<path d="M286 191l-34 49m34-49l38 49m-72 0h72"/>
|
|
28
|
+
<circle cx="286" cy="181" r="14" fill="#fff4da"/>
|
|
29
|
+
<circle cx="245" cy="249" r="14" fill="#fff4da"/>
|
|
30
|
+
<circle cx="331" cy="249" r="14" fill="#fff4da"/>
|
|
31
|
+
</g>
|
|
32
|
+
<g transform="translate(405 295) rotate(8)">
|
|
33
|
+
<path d="M0 20l19-18 17 12 17-8 12 22-12 17 7 19-23 10-15-12-22 5-8-23z" fill="#e8d8ba" stroke="#c7b28d" stroke-width="4"/>
|
|
34
|
+
<path d="M5 24l17 15 14-21 15 29" fill="none" stroke="#baa27b" stroke-width="3"/>
|
|
35
|
+
</g>
|
|
36
|
+
</svg>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import shutil
|
|
4
|
+
import sys
|
|
5
|
+
import types
|
|
6
|
+
|
|
7
|
+
try:
|
|
8
|
+
import agent.memory_provider # noqa: F401
|
|
9
|
+
except ImportError:
|
|
10
|
+
agent = types.ModuleType("agent")
|
|
11
|
+
memory_provider = types.ModuleType("agent.memory_provider")
|
|
12
|
+
|
|
13
|
+
class MemoryProvider:
|
|
14
|
+
pass
|
|
15
|
+
|
|
16
|
+
memory_provider.MemoryProvider = MemoryProvider
|
|
17
|
+
agent.memory_provider = memory_provider
|
|
18
|
+
sys.modules["agent"] = agent
|
|
19
|
+
sys.modules["agent.memory_provider"] = memory_provider
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def pytest_sessionfinish(session, exitstatus):
|
|
23
|
+
for name in (".pytest_cache",):
|
|
24
|
+
shutil.rmtree(name, ignore_errors=True)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import os
|
|
6
|
+
import shutil
|
|
7
|
+
import subprocess
|
|
8
|
+
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
TEXT_REPO = "litert-community/embeddinggemma-300m"
|
|
13
|
+
TEXT_FILES = ["embeddinggemma-300M_seq512_mixed-precision.tflite"]
|
|
14
|
+
TOKENIZER_REPO = "google/embeddinggemma-300m"
|
|
15
|
+
TOKENIZER_FILES = ["tokenizer.json", "tokenizer_config.json", "special_tokens_map.json"]
|
|
16
|
+
VISUAL_REPO = "Xenova/clip-vit-base-patch32"
|
|
17
|
+
VISUAL_FILES = [
|
|
18
|
+
"onnx/vision_model_quantized.onnx",
|
|
19
|
+
"onnx/text_model_quantized.onnx",
|
|
20
|
+
"tokenizer.json",
|
|
21
|
+
"tokenizer_config.json",
|
|
22
|
+
"config.json",
|
|
23
|
+
"preprocessor_config.json",
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def run(command: list[str], **kwargs) -> None:
|
|
28
|
+
print("+", " ".join(command))
|
|
29
|
+
subprocess.run(command, check=True, **kwargs)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def main() -> int:
|
|
33
|
+
parser = argparse.ArgumentParser(description="Install Hermes Local RAG without touching the Hermes checkout")
|
|
34
|
+
parser.add_argument("--home", default=os.environ.get("HERMES_HOME", str(Path.home() / ".hermes")))
|
|
35
|
+
parser.add_argument("--skip-models", action="store_true", help="Install code and dependencies without downloading model artifacts")
|
|
36
|
+
parser.add_argument("--check", action="store_true", help="Only verify an existing installation")
|
|
37
|
+
args = parser.parse_args()
|
|
38
|
+
|
|
39
|
+
home = Path(args.home).expanduser().resolve()
|
|
40
|
+
checkout = home / "hermes-agent"
|
|
41
|
+
python = Path(os.environ.get("HERMES_PYTHON", checkout / "venv" / "bin" / "python"))
|
|
42
|
+
hermes = shutil.which("hermes")
|
|
43
|
+
if not python.is_file() or not hermes:
|
|
44
|
+
raise SystemExit("Hermes installation not found. Install Hermes Agent first or set HERMES_HOME/HERMES_PYTHON.")
|
|
45
|
+
|
|
46
|
+
plugin_target = home / "plugins" / "local_rag"
|
|
47
|
+
text_target = home / "models" / "embeddinggemma-litert"
|
|
48
|
+
visual_target = home / "models" / "clip-onnx"
|
|
49
|
+
required = [plugin_target / "plugin.yaml", text_target / TEXT_FILES[0], visual_target / VISUAL_FILES[0], visual_target / VISUAL_FILES[1]]
|
|
50
|
+
if args.check:
|
|
51
|
+
missing = [str(path) for path in required if not path.exists()]
|
|
52
|
+
run([hermes, "memory", "status"])
|
|
53
|
+
if missing:
|
|
54
|
+
raise SystemExit("Missing installation artifacts:\n" + "\n".join(missing))
|
|
55
|
+
env = {**os.environ, "PYTHONPATH": str(home / "plugins")}
|
|
56
|
+
run([str(python), "-c", "from local_rag import LocalRagProvider; assert LocalRagProvider().is_available()"], env=env)
|
|
57
|
+
print("Hermes Local RAG installation is healthy.")
|
|
58
|
+
return 0
|
|
59
|
+
|
|
60
|
+
uv = shutil.which("uv")
|
|
61
|
+
if not uv:
|
|
62
|
+
raise SystemExit("uv is required because Hermes venvs may not include pip")
|
|
63
|
+
repository = Path(__file__).resolve().parent
|
|
64
|
+
run([uv, "pip", "install", "--python", str(python), str(repository)])
|
|
65
|
+
|
|
66
|
+
plugin_target.parent.mkdir(parents=True, exist_ok=True)
|
|
67
|
+
temporary = plugin_target.with_name("local_rag.installing")
|
|
68
|
+
shutil.rmtree(temporary, ignore_errors=True)
|
|
69
|
+
shutil.copytree(repository / "local_rag", temporary, ignore=shutil.ignore_patterns("__pycache__", "*.pyc"))
|
|
70
|
+
if plugin_target.exists():
|
|
71
|
+
backup = plugin_target.with_name("local_rag.previous")
|
|
72
|
+
shutil.rmtree(backup, ignore_errors=True)
|
|
73
|
+
plugin_target.replace(backup)
|
|
74
|
+
temporary.replace(plugin_target)
|
|
75
|
+
|
|
76
|
+
if not args.skip_models:
|
|
77
|
+
hf = python.parent / "hf"
|
|
78
|
+
if not hf.is_file():
|
|
79
|
+
raise SystemExit("Hugging Face CLI was not installed into the Hermes venv")
|
|
80
|
+
text_target.mkdir(parents=True, exist_ok=True)
|
|
81
|
+
visual_target.mkdir(parents=True, exist_ok=True)
|
|
82
|
+
try:
|
|
83
|
+
run([str(hf), "download", TEXT_REPO, *TEXT_FILES, "--local-dir", str(text_target)])
|
|
84
|
+
run([str(hf), "download", TOKENIZER_REPO, *TOKENIZER_FILES, "--local-dir", str(text_target)])
|
|
85
|
+
run([str(hf), "download", VISUAL_REPO, *VISUAL_FILES, "--local-dir", str(visual_target)])
|
|
86
|
+
except subprocess.CalledProcessError as exc:
|
|
87
|
+
raise SystemExit(
|
|
88
|
+
"Model download failed. EmbeddingGemma is gated: accept Gemma Terms on Hugging Face and run `hf auth login`, then rerun install.py."
|
|
89
|
+
) from exc
|
|
90
|
+
|
|
91
|
+
run([hermes, "config", "set", "memory.provider", "local_rag"])
|
|
92
|
+
print("Installed. Restart the Hermes gateway or start a new Desktop session, then run: python install.py --check")
|
|
93
|
+
return 0
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
if __name__ == "__main__":
|
|
97
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Hermes Local RAG
|
|
2
|
+
|
|
3
|
+
User-local `MemoryProvider` for private hybrid recall. It lives outside the Hermes checkout and survives normal updates.
|
|
4
|
+
|
|
5
|
+
## Storage and isolation
|
|
6
|
+
|
|
7
|
+
- Text: `~/.hermes/local-rag/memory.sqlite` (SQLite WAL + FTS5 + local vectors)
|
|
8
|
+
- Images: `~/.hermes/local-rag/visual.sqlite`
|
|
9
|
+
- Namespace: `<profile>:<platform-user>`, with Desktop/CLI mapped to `<profile>:local`
|
|
10
|
+
- Model weights are shared read-only; records are always filtered by namespace before ranking.
|
|
11
|
+
|
|
12
|
+
## Models
|
|
13
|
+
|
|
14
|
+
- Text: EmbeddingGemma 300M LiteRT `seq512`, 512-dimensional Matryoshka output by default; configurable to 128/256/512/768.
|
|
15
|
+
- Visual: quantized CLIP ViT-B/32 ONNX, 512 dimensions. Loaded lazily only for visual tools.
|
|
16
|
+
|
|
17
|
+
The 512-token artifact is intentional. Normal chunks are at most 384 words with 64-word overlap; context injection has a separate 3,200-character hard budget. A 2048-token model would increase interactive work without improving these bounded chunks.
|
|
18
|
+
|
|
19
|
+
Model weights are not distributed by this plugin. EmbeddingGemma remains subject to Gemma Terms; CLIP artifacts retain their upstream license.
|
|
20
|
+
|
|
21
|
+
## Dashboard setup
|
|
22
|
+
|
|
23
|
+
After installing the plugin from **Hermes Dashboard → Plugins**, open the **Local RAG** tab. The wizard installs dependencies, accepts a read-only Hugging Face token through a local password field, downloads the selected models, saves retention and embedding settings, activates the provider, and performs a health check. No Terminal is required for the normal path.
|
|
24
|
+
|
|
25
|
+
The token is passed directly to `huggingface_hub.login`, is never placed in a subprocess argument, response, config file, or setup log, and remains governed by Hugging Face's credential storage. Gemma Terms must still be accepted by the user in the browser.
|
|
26
|
+
|
|
27
|
+
## Ingestion
|
|
28
|
+
|
|
29
|
+
- User turns and session summaries are retained indefinitely by default.
|
|
30
|
+
- `~/.hermes/local-rag/config.json` can set `episodic_ttl_days` and `summary_ttl_days` to positive day counts; `null` means no expiry.
|
|
31
|
+
- Explicit preferences, decisions, and environment statements enter a review queue.
|
|
32
|
+
- Approved candidates and built-in Hermes memory writes become durable records.
|
|
33
|
+
- Assistant claims and raw tool output are never promoted as user facts.
|
|
34
|
+
- Secret-like content, `.env`, private keys, unsupported/binary files, oversized files, and paths outside the current project root are rejected before embedding.
|
|
35
|
+
|
|
36
|
+
## Retrieval
|
|
37
|
+
|
|
38
|
+
Hybrid ranking combines semantic similarity, FTS5 exact matches, importance, freshness, and a durable-memory boost. Low-scoring matches are omitted. Context injection includes provenance, limits repeated sources, and labels all retrieved text as untrusted data rather than instructions.
|
|
39
|
+
|
|
40
|
+
## Agent tools
|
|
41
|
+
|
|
42
|
+
`local_rag_remember`, `local_rag_search`, `local_rag_status`, `local_rag_forget`, `local_rag_review`, `local_rag_approve`, `local_rag_reject`, `local_rag_index_file`, `local_rag_prune`, `local_rag_index_image`, `local_rag_search_images`, `local_rag_forget_image`.
|
|
43
|
+
|
|
44
|
+
## Maintenance CLI
|
|
45
|
+
|
|
46
|
+
From the Hermes checkout:
|
|
47
|
+
|
|
48
|
+
```sh
|
|
49
|
+
PYTHONPATH="$HOME/.hermes/plugins" venv/bin/python -m local_rag.cli status
|
|
50
|
+
PYTHONPATH="$HOME/.hermes/plugins" venv/bin/python -m local_rag.cli --namespace default:local search "query"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Raw transcript backfill is disabled. Historical sessions must first undergo selective semantic extraction into normalized memory items; raw user turns, assistant output, and extractive summaries are never indexed automatically.
|
|
54
|
+
|
|
55
|
+
## Recovery
|
|
56
|
+
|
|
57
|
+
Hermes backup discovers `local-rag/` through `backup_paths()`. Schema upgrades create `memory.pre-v2.sqlite` before the first v2 migration. A changed embedding dimension stops startup with an explicit reindex error instead of corrupting existing vectors.
|