hermes-plugin-qdrant-memory 0.2.0__py3-none-any.whl
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_plugin_qdrant_memory-0.2.0.dist-info/METADATA +495 -0
- hermes_plugin_qdrant_memory-0.2.0.dist-info/RECORD +29 -0
- hermes_plugin_qdrant_memory-0.2.0.dist-info/WHEEL +5 -0
- hermes_plugin_qdrant_memory-0.2.0.dist-info/entry_points.txt +5 -0
- hermes_plugin_qdrant_memory-0.2.0.dist-info/licenses/LICENSE +21 -0
- hermes_plugin_qdrant_memory-0.2.0.dist-info/top_level.txt +1 -0
- qdrant_memory/__init__.py +33 -0
- qdrant_memory/cli.py +887 -0
- qdrant_memory/config.py +313 -0
- qdrant_memory/config_schema.py +111 -0
- qdrant_memory/dedupe.py +26 -0
- qdrant_memory/embedding.py +114 -0
- qdrant_memory/extraction.py +90 -0
- qdrant_memory/inventory.py +153 -0
- qdrant_memory/ledger.py +686 -0
- qdrant_memory/mcp_server.py +57 -0
- qdrant_memory/migration.py +525 -0
- qdrant_memory/models.py +130 -0
- qdrant_memory/ownership.py +48 -0
- qdrant_memory/plugin.yaml +13 -0
- qdrant_memory/progress.py +89 -0
- qdrant_memory/provider.py +568 -0
- qdrant_memory/qdrant_store.py +332 -0
- qdrant_memory/reset.py +317 -0
- qdrant_memory/retry.py +51 -0
- qdrant_memory/runtime.py +314 -0
- qdrant_memory/standalone.py +203 -0
- qdrant_memory/tools.py +81 -0
- qdrant_memory/version.py +3 -0
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hermes-plugin-qdrant-memory
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Durable Qdrant memory for Hermes, standalone CLI and local MCP
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Homepage, https://github.com/cnkang/hermes-plugin-qdrant-memory
|
|
7
|
+
Project-URL: Repository, https://github.com/cnkang/hermes-plugin-qdrant-memory
|
|
8
|
+
Project-URL: Issues, https://github.com/cnkang/hermes-plugin-qdrant-memory/issues
|
|
9
|
+
Project-URL: Changelog, https://github.com/cnkang/hermes-plugin-qdrant-memory/blob/main/CHANGELOG.md
|
|
10
|
+
Requires-Python: >=3.11
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: qdrant-client<2,>=1.15
|
|
14
|
+
Requires-Dist: httpx<1,>=0.28
|
|
15
|
+
Requires-Dist: portalocker<4,>=3.2
|
|
16
|
+
Provides-Extra: mcp
|
|
17
|
+
Requires-Dist: mcp<2,>=1.30; extra == "mcp"
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# Qdrant Memory for Hermes
|
|
21
|
+
|
|
22
|
+
[](https://github.com/cnkang/hermes-plugin-qdrant-memory/actions/workflows/ci.yml)
|
|
23
|
+
[](https://github.com/cnkang/hermes-plugin-qdrant-memory/actions/workflows/platform-compat.yml)
|
|
24
|
+
[](https://github.com/cnkang/hermes-plugin-qdrant-memory/actions/workflows/standalone.yml)
|
|
25
|
+
[](https://github.com/cnkang/hermes-plugin-qdrant-memory/actions/workflows/codeql.yml)
|
|
26
|
+
[](https://www.python.org/downloads/)
|
|
27
|
+
[](LICENSE)
|
|
28
|
+
|
|
29
|
+
> **v0.1.0 — limited technical preview.** Give Hermes Agent durable, private
|
|
30
|
+
> long-term memory: your conversations become searchable memories in your own
|
|
31
|
+
> Qdrant store, with recall, update and scoped deletion under your control.
|
|
32
|
+
> The preview supports one writer per destination, with the documented
|
|
33
|
+
> durability limits. See the [validation record](docs/validation.md) for the
|
|
34
|
+
> current certification.
|
|
35
|
+
|
|
36
|
+
[English](README.md) | [简体中文](README.zh-CN.md)
|
|
37
|
+
|
|
38
|
+
Native long-term memory plugin for Hermes Agent, implemented as a `MemoryProvider`.
|
|
39
|
+
Hermes performs extraction
|
|
40
|
+
through its trusted `ctx.llm` facade. Qdrant stores named dense vectors and schema-v1
|
|
41
|
+
payloads. No Mem0 SDK, separate LLM SDK, telemetry, or core modifications.
|
|
42
|
+
|
|
43
|
+
Available in the official [Hermes Plugin Catalog](https://hermes-agent.nousresearch.com/docs/plugins/qdrant-memory)
|
|
44
|
+
as a community-maintained plugin.
|
|
45
|
+
|
|
46
|
+
## How it works
|
|
47
|
+
|
|
48
|
+
```mermaid
|
|
49
|
+
flowchart LR
|
|
50
|
+
turn["Hermes turn"] --> admit["Provider callback"]
|
|
51
|
+
admit --> ledger[("SQLite ledger<br/>durable admission")]
|
|
52
|
+
ledger -.async.-> extract["LLM extraction +<br/>relation checks"]
|
|
53
|
+
extract --> store[("Qdrant<br/>dense vectors + payloads")]
|
|
54
|
+
ask["Recall / search"] --> search["Scoped dense search"]
|
|
55
|
+
search --> store
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Why this plugin
|
|
59
|
+
|
|
60
|
+
- Durable, private memory for Hermes Agent: conversations become searchable
|
|
61
|
+
memories in your own Qdrant store, with recall, update and scoped deletion.
|
|
62
|
+
- A native Hermes `MemoryProvider`, not Mem0. The `migrate mem0` command
|
|
63
|
+
imports existing Mem0 exports.
|
|
64
|
+
- Embedded Qdrant needs no separate service. The same code targets
|
|
65
|
+
self-hosted Server and Qdrant Cloud.
|
|
66
|
+
- A fully local setup works: embedded Qdrant and local Ollama keep the data
|
|
67
|
+
on your machine.
|
|
68
|
+
- Data locality follows the destination. Extraction uses the LLM configured
|
|
69
|
+
in Hermes, and embedding uses the configured embedding service; either can
|
|
70
|
+
be remote. See [Data flow and privacy](#data-flow-and-privacy).
|
|
71
|
+
- Not supported in this preview: multi-writer Server/Cloud, hybrid search and
|
|
72
|
+
a web UI.
|
|
73
|
+
|
|
74
|
+
## Additional compatibility with other agents
|
|
75
|
+
|
|
76
|
+
The plugin primarily provides Hermes Agent's durable memory integration. As an
|
|
77
|
+
additional capability, its shared backend can serve other agents through the
|
|
78
|
+
Runtime 0.2.0's `qdrant-memory --home PATH` JSON CLI and optional local stdio MCP
|
|
79
|
+
interface, without requiring Hermes. These interfaces support explicit scoped
|
|
80
|
+
memory operations and maintenance/migration; automatic extraction and prefetch
|
|
81
|
+
remain Hermes lifecycle features. See [standalone setup](docs/standalone.md) for
|
|
82
|
+
configuration and boundaries, and the agent-neutral
|
|
83
|
+
[qdrant-memory skill](https://github.com/cnkang/skills/tree/main/qdrant-memory)
|
|
84
|
+
for multi-agent installation and usage guidance.
|
|
85
|
+
|
|
86
|
+
The optional MCP server exposes four scoped tools: `qdrant_memory_search`,
|
|
87
|
+
`qdrant_memory_add`, `qdrant_memory_update` and `qdrant_memory_delete`. Compatible
|
|
88
|
+
clients launch it as a local stdio process and discover/call those tools;
|
|
89
|
+
maintenance and migration use the operator CLI. See the
|
|
90
|
+
[MCP capabilities and connection guide](docs/mcp.md) for setup, shared-memory
|
|
91
|
+
boundaries and the verified agent matrix. This is a tested source preview;
|
|
92
|
+
the published v0.1.0 plugin release does not include the MCP entrypoint.
|
|
93
|
+
|
|
94
|
+
## See it in action
|
|
95
|
+
|
|
96
|
+

|
|
97
|
+
|
|
98
|
+
The recording shows the full flow on a clean profile: install from the
|
|
99
|
+
official Hermes Plugin Catalog, teach a preference, wait for the background
|
|
100
|
+
extraction, recall it in a new session, and clean up the demo scope. All steps
|
|
101
|
+
run in embedded mode. `scripts/demo.sh` reproduces the same walkthrough with
|
|
102
|
+
the pinned release.
|
|
103
|
+
|
|
104
|
+
## Install
|
|
105
|
+
|
|
106
|
+
Requirements: Python 3.11+, a compatible Hermes installation, and a reachable
|
|
107
|
+
embedding service. The minimum supported Hermes release is v0.21.5 (v2026.9.24).
|
|
108
|
+
The [CI services](docs/ci.md) page documents the tested host versions.
|
|
109
|
+
The default model needs Ollama and enough local resources
|
|
110
|
+
to serve `qwen3-embedding:4b`.
|
|
111
|
+
|
|
112
|
+
Choose the **active profile's** home explicitly. Do not reuse another profile's data.
|
|
113
|
+
|
|
114
|
+
**Recommended: install from the official Hermes Plugin Catalog.**
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
export HERMES_HOME="/absolute/path/to/your/hermes-profile"
|
|
118
|
+
ollama pull qwen3-embedding:4b
|
|
119
|
+
# Start Ollama if it is not running. Keep its service available.
|
|
120
|
+
hermes plugins install qdrant-memory
|
|
121
|
+
hermes plugins enable qdrant-memory
|
|
122
|
+
hermes memory setup
|
|
123
|
+
hermes config set memory.provider qdrant-memory
|
|
124
|
+
hermes qdrant-memory init
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The install resolves the catalog's reviewed commit and prints the entry's declared
|
|
128
|
+
tools, requirements and known issues before it clones anything.
|
|
129
|
+
`hermes plugins enable` prepares the declared dependencies through Hermes PM.
|
|
130
|
+
|
|
131
|
+
**Version-locked: install the pinned release through the Hermes CLI.**
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
export HERMES_HOME="/absolute/path/to/your/hermes-profile"
|
|
135
|
+
ollama pull qwen3-embedding:4b
|
|
136
|
+
# Start Ollama if it is not running. Keep its service available.
|
|
137
|
+
hermes plugins install https://github.com/cnkang/hermes-plugin-qdrant-memory \
|
|
138
|
+
--ref 5babd3e4b4c022aad38a2b6db82cbd5b601f1ef8 # v0.1.0 release commit
|
|
139
|
+
hermes plugins enable qdrant-memory
|
|
140
|
+
hermes memory setup
|
|
141
|
+
hermes config set memory.provider qdrant-memory
|
|
142
|
+
hermes qdrant-memory init
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
For this version-locked form, `hermes plugins install` checks out the given ref, and
|
|
146
|
+
`hermes plugins enable` prepares the declared dependencies through Hermes PM.
|
|
147
|
+
`--ref` takes a full 40-character commit SHA; the
|
|
148
|
+
[releases page](https://github.com/cnkang/hermes-plugin-qdrant-memory/releases)
|
|
149
|
+
lists the release commits. Do not pip-install into a managed Hermes
|
|
150
|
+
environment. Omit `--ref` to track `main`, the development line.
|
|
151
|
+
|
|
152
|
+
**Alternative: clone the release tag manually.**
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
export HERMES_HOME="/absolute/path/to/your/hermes-profile"
|
|
156
|
+
mkdir -p "$HERMES_HOME/plugins"
|
|
157
|
+
RELEASE_TAG=v0.1.0 # set a published release tag
|
|
158
|
+
git clone --branch "$RELEASE_TAG" --depth 1 \
|
|
159
|
+
https://github.com/cnkang/hermes-plugin-qdrant-memory.git \
|
|
160
|
+
"$HERMES_HOME/plugins/qdrant-memory"
|
|
161
|
+
ollama pull qwen3-embedding:4b
|
|
162
|
+
# Start Ollama if it is not running. Keep its service available.
|
|
163
|
+
hermes memory setup
|
|
164
|
+
hermes config set memory.provider qdrant-memory
|
|
165
|
+
hermes qdrant-memory init
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Then verify the install:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
hermes qdrant-memory status
|
|
172
|
+
hermes qdrant-memory doctor
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
A healthy install reports the destination, the embedding service and the
|
|
176
|
+
schema fingerprint. `doctor` validates runtime discovery, manifest parsing,
|
|
177
|
+
import and registration. For development installs, see
|
|
178
|
+
[development setup](docs/development.md).
|
|
179
|
+
|
|
180
|
+
The release notes, supported Hermes/Python versions and the current
|
|
181
|
+
limitations live in [docs/releases/v0.1.0.md](docs/releases/v0.1.0.md);
|
|
182
|
+
`main` stays the development line.
|
|
183
|
+
|
|
184
|
+
For local development, symlink the repository into a disposable profile:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
mkdir -p "$HERMES_HOME/plugins"
|
|
188
|
+
ln -s /path/to/hermes-plugin-qdrant-memory "$HERMES_HOME/plugins/qdrant-memory"
|
|
189
|
+
hermes memory setup
|
|
190
|
+
hermes config set memory.provider qdrant-memory
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
Restart the conversation after configuration changes. Existing system prompts
|
|
194
|
+
and toolsets stay fixed for prompt caching. Packaged installations expose the
|
|
195
|
+
`hermes_agent.memory_providers` entry point and keep `cli.py` and `config_schema.py`
|
|
196
|
+
next to the package entry point.
|
|
197
|
+
|
|
198
|
+
Defaults use embedded Qdrant and Ollama `qwen3-embedding:4b` (2560 dimensions).
|
|
199
|
+
Run the embedding service and provision that model before you activate the provider.
|
|
200
|
+
For server/Cloud, configure the mode in `$HERMES_HOME/qdrant-memory.json`. Supply
|
|
201
|
+
`QDRANT_URL` / `QDRANT_API_KEY` in the active profile's secret scope.
|
|
202
|
+
|
|
203
|
+
## Capabilities
|
|
204
|
+
|
|
205
|
+
- Embedded, self-hosted server and Cloud using the same Qdrant client.
|
|
206
|
+
- Ollama `/api/embed` and OpenAI-compatible `/v1/embeddings`, with strict probe,
|
|
207
|
+
vector-count/dimension validation and pipeline fingerprint checks.
|
|
208
|
+
- Main LLM inheritance, plugin auxiliary task routing and operator-trusted overrides.
|
|
209
|
+
- User/agent scope filtering for recall, exact-ID update and deletion.
|
|
210
|
+
- Turn persistence to the plugin's private SQLite ledger after Hermes admits the
|
|
211
|
+
provider callback. Serialized writes, cached session recall and builtin memory
|
|
212
|
+
mirroring use authoritative `previous_content`.
|
|
213
|
+
- SQLite WAL event/operation ledger, transport retries and restart recovery.
|
|
214
|
+
- Source-ID-only Mem0 JSON/Qdrant migration, re-embedding, dry runs, resumable
|
|
215
|
+
manifests, supplemental updates, and verification of IDs and payload hashes.
|
|
216
|
+
- Read-only `list` inventory, portable `export` (Mem0-importable JSON) and a
|
|
217
|
+
durable scoped `delete-all` with prepared-write fencing.
|
|
218
|
+
|
|
219
|
+
Unlike hosted memory services, your memory data lives in your own Qdrant
|
|
220
|
+
destination. The plugin makes no calls to external memory services. Its
|
|
221
|
+
private SQLite ledger (pending operations, dedupe/retry bookkeeping and session
|
|
222
|
+
mappings) stays in the local Hermes home. Back up that home together with your
|
|
223
|
+
Qdrant data. Migration from Mem0 is one-way, and version 0.1 has no vector
|
|
224
|
+
reuse or hybrid retrieval.
|
|
225
|
+
|
|
226
|
+
Similarity is a candidate-selection signal, not proof that two facts are identical.
|
|
227
|
+
`SAME` skips, `SUPERSEDES` updates, `CONFLICT` creates a linked record, and
|
|
228
|
+
`UNRELATED` adds a record. Migration uses source IDs instead of semantic merging.
|
|
229
|
+
|
|
230
|
+
The four agent tools are `qdrant_memory_search`, `qdrant_memory_add`,
|
|
231
|
+
`qdrant_memory_update`, and `qdrant_memory_delete`. Maintenance stays in the CLI:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
hermes qdrant-memory status
|
|
235
|
+
hermes qdrant-memory init
|
|
236
|
+
hermes qdrant-memory doctor
|
|
237
|
+
hermes qdrant-memory stats
|
|
238
|
+
hermes qdrant-memory verify
|
|
239
|
+
hermes qdrant-memory retry
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
`status` is local-only. `doctor` and `verify` probe existing collections without
|
|
243
|
+
creating or repairing them. Run `init` after first-time configuration to probe
|
|
244
|
+
embeddings, create the collection, record its pipeline fingerprint and build
|
|
245
|
+
Server/Cloud payload indexes. It makes no LLM calls and writes no conversation
|
|
246
|
+
memories. Repeated runs validate the existing collection. Incompatible dimensions,
|
|
247
|
+
distance or fingerprint fail without overwriting existing data.
|
|
248
|
+
When the collection exists, `init` asks for `use` (the default on Enter) or `clear`.
|
|
249
|
+
Reuse validates the named dense vector, dimensions, distance and pipeline identity,
|
|
250
|
+
then checks every stored memory's payload, content hash and vector. A validation
|
|
251
|
+
failure returns a nonzero exit code. The plugin cannot reuse a nonempty
|
|
252
|
+
collection without a trusted fingerprint.
|
|
253
|
+
Clear probes embeddings first, then deletes and rebuilds the target collection and
|
|
254
|
+
discards that destination's local replay work and migration records. The plugin
|
|
255
|
+
keeps other destinations and the transcript provenance quarantine. Clearing is
|
|
256
|
+
irreversible, and deletion/recreation is not atomic. Rerun `init` if remote
|
|
257
|
+
recreation fails.
|
|
258
|
+
An interrupted clear leaves a durable reset intent. Other destination commands fail
|
|
259
|
+
with `reset_recovery_required`. Rerun `init` for the same destination to resume the
|
|
260
|
+
already authorized reset before you enable the provider.
|
|
261
|
+
For scripts, explicitly pass `--existing use` or `--existing clear`. The `clear`
|
|
262
|
+
choice authorizes deletion. `--collection NAME` overrides only this command's
|
|
263
|
+
target, not the collection configured for subsequent agent sessions.
|
|
264
|
+
`init`, `migrate` and `retry` require exclusive writer ownership in all deployment
|
|
265
|
+
modes. The OS lease coordinates local processes that use that profile destination.
|
|
266
|
+
It is not a distributed lock. Stop every Hermes session or gateway on every host
|
|
267
|
+
that writes to the same destination before you run them. If `doctor` already
|
|
268
|
+
reports `ok: true`, the collection is ready. Initialization is unnecessary. Remote
|
|
269
|
+
`doctor`, `stats` and `verify` can inspect it while the writer runs.
|
|
270
|
+
`retry` requeues failed events for the next provider
|
|
271
|
+
startup and retries prepared operations. Stop the agent before you run maintenance
|
|
272
|
+
on an embedded store. Qdrant's local persistence permits only one client process.
|
|
273
|
+
|
|
274
|
+
## Memory inventory, export and scoped deletion
|
|
275
|
+
|
|
276
|
+
```bash
|
|
277
|
+
hermes qdrant-memory list # read-only inventory
|
|
278
|
+
hermes qdrant-memory export --output backup.json # portable JSON for re-import
|
|
279
|
+
hermes qdrant-memory delete-all --user alice --confirm
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
`list` reports stored memories with scope, provenance and timestamps. It also
|
|
283
|
+
reports the destination's pending/failed operation counts. Use `--user` and
|
|
284
|
+
`--agent` to filter. Omitting both covers the whole collection. `--limit`
|
|
285
|
+
bounds the output, and the command refuses `--agent` without `--user`.
|
|
286
|
+
`export` writes every stored memory, optionally one scope, as portable JSON in
|
|
287
|
+
the shape the Mem0 importer accepts. `hermes qdrant-memory migrate mem0
|
|
288
|
+
--source-json backup.json` then restores it into a fresh destination (imports
|
|
289
|
+
re-embed, and version 0.1 has no vector reuse). Round trips preserve text,
|
|
290
|
+
scope, categories and timestamps. Mem0-migrated memories re-import to the same
|
|
291
|
+
points, and native memories keep their original point UUID in the exported
|
|
292
|
+
record for provenance. The plugin writes exports owner-only and refuses to
|
|
293
|
+
overwrite without `--force`. An export covers stored memories only. Pending
|
|
294
|
+
events, retry history and crash-recovery state stay in the local ledger. Back
|
|
295
|
+
up the profile home for a full recovery point.
|
|
296
|
+
|
|
297
|
+
`delete-all` durably deletes stored memories and pending work for one scope
|
|
298
|
+
(`--user` required). It records a reset-style intent first. Then it fences every
|
|
299
|
+
enumerated point and every prepared write for that scope, including writes
|
|
300
|
+
whose points were never stored. It invalidates admitted-but-unprocessed turn
|
|
301
|
+
events for the scope, deletes the scope in one filtered operation, and clears
|
|
302
|
+
the intent only after the scope becomes empty. A scope is exactly one
|
|
303
|
+
(user, agent) pair. Omitting `--agent` selects the no-agent scope, and the
|
|
304
|
+
default profile scope uses an agent (`hermes`). Pass `--agent hermes` to
|
|
305
|
+
target it, or `--all-agents` to delete every agent scope of the user. Without
|
|
306
|
+
`--all-agents`, the result reports `other_agent_scopes` when other agent
|
|
307
|
+
scopes still hold memories. A literal `*` is an ordinary agent id, not a
|
|
308
|
+
wildcard. `--dry-run` previews the per-scope counts;
|
|
309
|
+
`--confirm` authorizes deletion. An interrupted deletion fails closed: other
|
|
310
|
+
commands and provider startup return `scope_delete_recovery_required` until
|
|
311
|
+
`delete-all --confirm` resumes it. Deletion intents are versioned and explicit.
|
|
312
|
+
A pre-versioned intent cannot show whether `*` is a single agent or all agents,
|
|
313
|
+
so the plugin refuses it (`scope_delete_legacy_intent`). Resolve it with
|
|
314
|
+
`--resolve-legacy single_agent`, or with `--resolve-legacy all_agents` when the
|
|
315
|
+
record's agent is `*` or absent. Turns admitted after the deletion can still
|
|
316
|
+
add new memories; everything admitted before it — stored memories, prepared
|
|
317
|
+
writes and unprocessed turn events — is removed or invalidated. `list`,
|
|
318
|
+
`export` and `delete-all` do not require the embedding service.
|
|
319
|
+
|
|
320
|
+
## Data flow and privacy
|
|
321
|
+
|
|
322
|
+
This provider sends data only toward services you configure. What each component
|
|
323
|
+
carries and where it can go:
|
|
324
|
+
|
|
325
|
+
| Component | Carries | Destination |
|
|
326
|
+
| --- | --- | --- |
|
|
327
|
+
| Chat / agent turns | Your conversation | The model configured for the Hermes session |
|
|
328
|
+
| Memory extraction (`llm.mode: inherit`) | The turn's user and assistant text | The same session model — with a cloud model, turn text reaches that cloud |
|
|
329
|
+
| Relation checks | The candidate memory and the similar stored memory | Same routing as extraction; runs only when similarity selects a review candidate |
|
|
330
|
+
| Embeddings (`embedding`) | Memory and search text | Ollama by default, or your OpenAI-compatible endpoint |
|
|
331
|
+
| Storage (`qdrant`) | Memory payloads and provenance; the ledger stays local | Embedded local path, self-hosted server, or Qdrant Cloud |
|
|
332
|
+
|
|
333
|
+
Three common deployments:
|
|
334
|
+
|
|
335
|
+
| Deployment | Chat model | Extraction LLM | Embeddings | Storage |
|
|
336
|
+
| --- | --- | --- | --- | --- |
|
|
337
|
+
| Fully offline | local (for example Ollama) | inherits the local model | local Ollama | embedded local |
|
|
338
|
+
| Hybrid | cloud | inherits the cloud model by default | local Ollama | embedded local |
|
|
339
|
+
| Full cloud | cloud | cloud | OpenAI-compatible endpoint | Qdrant Cloud |
|
|
340
|
+
|
|
341
|
+
A fully offline setup needs enough local compute for the chat model and the
|
|
342
|
+
embeddings together. On a 24 GB host, a 27B local chat model plus local
|
|
343
|
+
embeddings exceeded comfortable VRAM during validation. Local-model turns can
|
|
344
|
+
take minutes each. Budget accordingly or use a smaller local model.
|
|
345
|
+
|
|
346
|
+
In the hybrid layout, extraction and relation checks inherit the session model.
|
|
347
|
+
Route them elsewhere with `llm.mode: task` (the plugin's auxiliary task on a
|
|
348
|
+
local model) or `llm.mode: override` (an explicit provider and model).
|
|
349
|
+
Extraction instructions exclude obvious credentials and transient statuses, but
|
|
350
|
+
any configured LLM or Qdrant destination can see the memories it processes.
|
|
351
|
+
Treat them accordingly. Logical scrubbing of the local
|
|
352
|
+
ledger is not secure erasure. See [operations](docs/operations.md) and
|
|
353
|
+
[security](docs/security.md).
|
|
354
|
+
|
|
355
|
+
Extraction and relation checks run as Hermes auxiliary calls. Their per-task
|
|
356
|
+
timeout defaults to 30 seconds, and a slow local model can exceed it easily.
|
|
357
|
+
Raise `auxiliary.qdrant_memory_extraction.timeout` (seconds) for fully local
|
|
358
|
+
deployments. A timed-out extraction becomes failed work, and
|
|
359
|
+
`hermes qdrant-memory retry` requeues it.
|
|
360
|
+
|
|
361
|
+
## Configuration and migration
|
|
362
|
+
|
|
363
|
+
Behavior lives in `$HERMES_HOME/qdrant-memory.json`. Credentials belong in the
|
|
364
|
+
active profile's Hermes secret scope. Defaults use embedded Qdrant.
|
|
365
|
+
During setup, the wizard reuses existing `QDRANT_URL` and `QDRANT_API_KEY` from
|
|
366
|
+
the active profile's environment without another prompt. Setup reports their
|
|
367
|
+
presence without showing values, asks only for missing settings and saves environment
|
|
368
|
+
references rather than copying supplied values or keys. An environment URL replaces
|
|
369
|
+
any older explicit URL in the saved plugin settings. For server or
|
|
370
|
+
Cloud, set `qdrant.mode`, collection and endpoint. Cloud requires HTTPS and a
|
|
371
|
+
Database API key. [Configuration examples and defaults](docs/configuration.md)
|
|
372
|
+
cover Ollama, OpenAI-compatible embeddings, LLM routing and explicit fallbacks.
|
|
373
|
+
|
|
374
|
+
Use a separate target collection and keep the Mem0 source unchanged:
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
hermes qdrant-memory migrate mem0 --source-json /path/to/export.json --dry-run
|
|
378
|
+
# Stop CLI/foreground writers; for an installed background gateway:
|
|
379
|
+
hermes gateway status
|
|
380
|
+
hermes gateway stop
|
|
381
|
+
hermes qdrant-memory migrate mem0 --source-json /path/to/export.json \
|
|
382
|
+
--target-collection hermes_qdrant_memory --resume --verify
|
|
383
|
+
hermes qdrant-memory verify --collection hermes_qdrant_memory
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
Re-embedding is the default. `--resume` needs the same snapshot and pipeline.
|
|
387
|
+
Add `--retry-failed` to retry failed operations from that manifest. Migration
|
|
388
|
+
verification checks exact IDs, scope and payload hashes, not just record count.
|
|
389
|
+
Canceled migration records become terminal `SUPERSEDED` work. They never count
|
|
390
|
+
as successful writes. Resume preserves later deletion intent. `--verify` reports
|
|
391
|
+
the conflict as `migration_superseded` with a nonzero exit code. While failed
|
|
392
|
+
records remain, `--verify` reports `migration_incomplete` instead. Correct and
|
|
393
|
+
resume the failures before any conflict review or deliberate fresh import. Only
|
|
394
|
+
a fresh import or changed snapshot authorizes replanning.
|
|
395
|
+
Recovery reads operations and events in finite bounded pages. Retained ledger
|
|
396
|
+
history still needs disk-capacity monitoring.
|
|
397
|
+
Before a real import, stop all sessions/gateways writing to the target, including
|
|
398
|
+
for Server/Cloud. `writer_busy` requires stopping the active writer, not deleting
|
|
399
|
+
lock or ledger files. A successful dry-run does not check writer ownership.
|
|
400
|
+
Read the [migration guide](docs/migration-from-mem0.md) for executable gateway
|
|
401
|
+
stop/start, migration, verification and interrupted-import recovery commands.
|
|
402
|
+
|
|
403
|
+
## Operations and security
|
|
404
|
+
|
|
405
|
+
The private SQLite ledger can contain raw turn events and prepared payloads. It
|
|
406
|
+
logically scrubs committed event bodies and committed/superseded operation bodies,
|
|
407
|
+
except operations still needed by an incomplete migration manifest. Identity/status
|
|
408
|
+
rows and manifests remain. Pending/failed work retains its body for recovery. There
|
|
409
|
+
is no time-based expiry for ledger rows or manifests. Deleting a Qdrant memory does
|
|
410
|
+
not purge pending or failed ledger work. Treat `state.db`, SQLite WAL/SHM sidecars,
|
|
411
|
+
copied snapshots and backups as sensitive. Stop the agent before you back up the
|
|
412
|
+
ledger with the embedded store. `init --existing clear` clears the selected
|
|
413
|
+
collection's ledger rows, but logical scrubbing/reset is not secure erasure from disk
|
|
414
|
+
pages or previously copied backups. Do not delete `state.db` to recover failed work.
|
|
415
|
+
Changing embedding identity requires a new collection.
|
|
416
|
+
|
|
417
|
+
The durability guarantee starts only after Hermes calls the provider's `sync_turn`
|
|
418
|
+
callback and the plugin commits the event to SQLite. Hermes currently submits that
|
|
419
|
+
callback to an in-memory background queue. An abrupt host exit or its bounded
|
|
420
|
+
shutdown can abandon work that has not reached plugin admission. After ledger
|
|
421
|
+
admission, the plugin replays pending events and prepared operations after restart.
|
|
422
|
+
This plugin ledger does not make the earlier host queue durable.
|
|
423
|
+
|
|
424
|
+
Tool arguments cannot override user/agent scope. Automatic writes exclude bot
|
|
425
|
+
and non-primary-agent turns. Treat recalled content as untrusted data. See
|
|
426
|
+
[security](docs/security.md), [operating procedures](docs/operations.md),
|
|
427
|
+
[troubleshooting](docs/troubleshooting.md) and [architecture](docs/architecture.md).
|
|
428
|
+
|
|
429
|
+
## Compatibility and scope
|
|
430
|
+
|
|
431
|
+
Version 0.1 implements dense retrieval. Hybrid sparse vectors, RRF/DBSF, reranking
|
|
432
|
+
and recency weighting remain future capabilities. The plugin rejects unsupported
|
|
433
|
+
config. Named `dense` vectors preserve a path to future sparse vectors.
|
|
434
|
+
|
|
435
|
+
The plugin feature-detects embedding `inherit` and requires an explicit
|
|
436
|
+
`inherit_fallback`. The future host facade must provide `dimensions`,
|
|
437
|
+
`fingerprint`, `embed_documents()` and `embed_query()`. Current Hermes has no
|
|
438
|
+
documented global embedding facade.
|
|
439
|
+
|
|
440
|
+
Compatibility requires Hermes `MemoryProvider`, checkpoint v2, trusted turn authors,
|
|
441
|
+
authoritative builtin `previous_content`, scoped secrets and context threads.
|
|
442
|
+
Earlier tags have incomplete contracts. The minimum supported release is v0.21.5 (v2026.9.24). See
|
|
443
|
+
[validation](docs/validation.md) for tested environments and remaining live-service
|
|
444
|
+
checks. Read [configuration](docs/configuration.md), [migration](docs/migration-from-mem0.md),
|
|
445
|
+
[security](docs/security.md) and [operations](docs/operations.md) before deployment.
|
|
446
|
+
|
|
447
|
+
## Development
|
|
448
|
+
|
|
449
|
+
Run Ruff lint and format checks before you commit. Install the repository
|
|
450
|
+
pre-commit hook as described in [development setup](docs/development.md). The hook
|
|
451
|
+
checks the staged snapshot. CI runs lint, both Python versions, Snyk and
|
|
452
|
+
SonarCloud. See [CI services](docs/ci.md) for the tested host versions and lanes.
|
|
453
|
+
|
|
454
|
+
Build isolated dependency environments with Hermes PM. Then run the host's
|
|
455
|
+
canonical test runner against this repository's tests. The tests import the real
|
|
456
|
+
host and use a temporary `HERMES_HOME`.
|
|
457
|
+
|
|
458
|
+
```bash
|
|
459
|
+
cd /path/to/hermes-agent
|
|
460
|
+
python -m pm.build_env --source /path/to/hermes-agent --group test \
|
|
461
|
+
--export-requirements /tmp/hermes-qdrant-test-requirements.txt
|
|
462
|
+
python -c 'import sys, tomllib; from pathlib import Path; p = tomllib.loads(Path(sys.argv[1]).read_text()); print("\n".join(p["project"]["dependencies"] + p["dependency-groups"]["test"]))' \
|
|
463
|
+
/path/to/hermes-plugin-qdrant-memory/pyproject.toml >> /tmp/hermes-qdrant-test-requirements.txt
|
|
464
|
+
python -m pm.build_env --out /path/to/hermes-plugin-qdrant-memory/.test-env \
|
|
465
|
+
--requirements /tmp/hermes-qdrant-test-requirements.txt
|
|
466
|
+
HERMES_PYTHON=/path/to/hermes-plugin-qdrant-memory/.test-env/bin/python \
|
|
467
|
+
scripts/run_tests.sh /path/to/hermes-plugin-qdrant-memory/tests -j 1 --file-retries 0
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
The build reads the plugin's `test` development dependency group from
|
|
471
|
+
`pyproject.toml`. The tested host PM exports runtime requirements only. Append the
|
|
472
|
+
plugin runtime dependencies and test group before you build the combined
|
|
473
|
+
environment.
|
|
474
|
+
|
|
475
|
+
Run the real embedding pilot from the plugin checkout with the host import path:
|
|
476
|
+
|
|
477
|
+
```bash
|
|
478
|
+
PYTHONPATH=/path/to/hermes-agent .test-env/bin/python scripts/evaluate.py
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
It uses a temporary embedded collection and UTF-8 JSON dataset. A custom dataset
|
|
482
|
+
contains `memories` objects with `id`/`text`, and `queries` with `query`/`relevant_ids`.
|
|
483
|
+
The default fixture now contains 24 labeled queries, including Chinese, English,
|
|
484
|
+
mixed-language and hard-negative cases. The
|
|
485
|
+
[original 12-query recording](docs/retrieval-baseline.json) is a historical
|
|
486
|
+
synthetic regression baseline; rerun the current fixture for current measurements.
|
|
487
|
+
These fixtures do not establish production recall quality. See the [recovery benchmark](docs/recovery-benchmark.md)
|
|
488
|
+
for a separate synthetic replay and retained-storage measurement.
|
|
489
|
+
|
|
490
|
+
CI runs tests, SonarCloud quality gates and Snyk dependency/code scans.
|
|
491
|
+
See [CI service setup](docs/ci.md) and [validation evidence](docs/validation.md).
|
|
492
|
+
|
|
493
|
+
## License
|
|
494
|
+
|
|
495
|
+
MIT. Copyright © 2026 Kang Liu. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
hermes_plugin_qdrant_memory-0.2.0.dist-info/licenses/LICENSE,sha256=tI3MOOwKR6ncyQZfZF_QsRjB8_yoGYttXJp5oeLlqZQ,1065
|
|
2
|
+
qdrant_memory/__init__.py,sha256=Ai3Rmn7hGn5__h86O79SYuQPIKjqulcqiMgnSzb7IFU,1185
|
|
3
|
+
qdrant_memory/cli.py,sha256=DGeSVP-9HDXRXe-m46s5vr8YdSp_wjNcU5dahrIsQEc,36979
|
|
4
|
+
qdrant_memory/config.py,sha256=tf2CDK7vZSR6vUNcTSw8ErquqC2cuWrTAUqZG5Se3nc,11479
|
|
5
|
+
qdrant_memory/config_schema.py,sha256=llf5KFkkId6lARHNhZltsSkXM3m6T48bZ4C9TTuuKIQ,3986
|
|
6
|
+
qdrant_memory/dedupe.py,sha256=rdxca38dAH5cQ0PE3RQMex0xkBDFKozZC6GmULKswVk,1004
|
|
7
|
+
qdrant_memory/embedding.py,sha256=_D69zwdGl9f-5e11Um-n8nrT5h8pmBOUFBa0_0y7BVc,4802
|
|
8
|
+
qdrant_memory/extraction.py,sha256=3Mc5wp9iw75Zuo3x13jsDZXwRaq1fNT1JjFD4WI1yxs,3612
|
|
9
|
+
qdrant_memory/inventory.py,sha256=U8_Mxktm2rJ6_8eisGOjG3nhLYn9b2upJ4MleVDOQ_w,5921
|
|
10
|
+
qdrant_memory/ledger.py,sha256=TPgi7mXQxxuvHmHEuMu2FY_mDeWCWEyx_AtaE9sZ6qQ,31006
|
|
11
|
+
qdrant_memory/mcp_server.py,sha256=fyda_IeUPpT1vUuHGyCF6XHFuKDvRsKlBEOPj71wrYM,1930
|
|
12
|
+
qdrant_memory/migration.py,sha256=yMwB_f4dwKpFAgcSZNyucIsLAzDBzwe0EztPj3ZIGL8,21056
|
|
13
|
+
qdrant_memory/models.py,sha256=ZAbP89GXhzDsc6F629l2F7-mIxY8fhfrDMbJosei6bs,4319
|
|
14
|
+
qdrant_memory/ownership.py,sha256=e4ANHuwmCTpXrGXzZqPL--5-B2ZVfC-yq1FiE8jhPn0,1844
|
|
15
|
+
qdrant_memory/plugin.yaml,sha256=aja4fnCgVwnQ9fSdsMHrQz_9bwLT8ZQ6kDTmLINgUfA,376
|
|
16
|
+
qdrant_memory/progress.py,sha256=afUBQPAzXwklIRaKZcvsOJA5azfa0BF_7Ebf48POA6Y,3356
|
|
17
|
+
qdrant_memory/provider.py,sha256=7NpO1lHEU6YiI0WWDhR_5kzIeGyFJu047AcqXoMQ1jo,25601
|
|
18
|
+
qdrant_memory/qdrant_store.py,sha256=E4JNpHbDDrix2O9xBZiZYj9m9yCVX34uJakNDbyUp3g,13270
|
|
19
|
+
qdrant_memory/reset.py,sha256=VNkGCjq55I0Ftz328LhPQtZqZe2xpog_T4ceDmoSks8,11728
|
|
20
|
+
qdrant_memory/retry.py,sha256=o9K57Fnqf_71b0oGgSiY3MWeWKMZ72rP1IwXJf1ZGq0,1926
|
|
21
|
+
qdrant_memory/runtime.py,sha256=GN7onnqL6zqsYtxe4QtDp85FHmuAOke-8B5YVQ7Ei3Y,13452
|
|
22
|
+
qdrant_memory/standalone.py,sha256=Srlua0lD9Kk6esziNMH-GGh5HsniyBvGty3aBajTu78,8308
|
|
23
|
+
qdrant_memory/tools.py,sha256=oVrQc5qJXls9fzC_JaeIKDTB_ez1oZPKOy-bEwe55Dk,3178
|
|
24
|
+
qdrant_memory/version.py,sha256=Uj6-dVJM_cPUdVZYG1ZaTqo36WsZC638v-k5eka7TcU,95
|
|
25
|
+
hermes_plugin_qdrant_memory-0.2.0.dist-info/METADATA,sha256=DTWnuHyNpb9vHdn47wJxotovQGXSL9QeOiixFs5IuK4,26949
|
|
26
|
+
hermes_plugin_qdrant_memory-0.2.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
27
|
+
hermes_plugin_qdrant_memory-0.2.0.dist-info/entry_points.txt,sha256=arUy4YnIqnxN2Q0-h8U_8jFy3Bhpt8zM-89Sd6_hico,136
|
|
28
|
+
hermes_plugin_qdrant_memory-0.2.0.dist-info/top_level.txt,sha256=vEef3Eaq6Ru40jtIOB2b2Aww86DmH6cUdHZW-SwwBD4,14
|
|
29
|
+
hermes_plugin_qdrant_memory-0.2.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kang Liu
|
|
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 @@
|
|
|
1
|
+
qdrant_memory
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Native Hermes MemoryProvider registration, with no import-time I/O."""
|
|
2
|
+
|
|
3
|
+
from .version import VERSION as __version__
|
|
4
|
+
|
|
5
|
+
__all__ = ["register", "__version__"]
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def register(ctx):
|
|
9
|
+
"""Register a provider with the host memory discovery context."""
|
|
10
|
+
ctx.register_memory_provider(create_provider(ctx))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def create_provider(ctx):
|
|
14
|
+
"""Create a provider and register its auxiliary task on a trusted runtime context."""
|
|
15
|
+
from .provider import QdrantMemoryProvider
|
|
16
|
+
|
|
17
|
+
# Some Hermes memory discovery collectors expose registration only. Build
|
|
18
|
+
# the same named PluginContext so LLM calls still traverse the host trust gate.
|
|
19
|
+
if not hasattr(ctx, "llm"):
|
|
20
|
+
from hermes_cli.plugins import PluginContext, PluginManifest, get_plugin_manager
|
|
21
|
+
|
|
22
|
+
runtime_ctx = PluginContext(
|
|
23
|
+
PluginManifest(name="qdrant-memory", key="qdrant-memory"), get_plugin_manager()
|
|
24
|
+
)
|
|
25
|
+
else:
|
|
26
|
+
runtime_ctx = ctx
|
|
27
|
+
|
|
28
|
+
runtime_ctx.register_auxiliary_task(
|
|
29
|
+
"qdrant_memory_extraction",
|
|
30
|
+
display_name="Qdrant Memory Extraction",
|
|
31
|
+
description="Extract and reconcile durable memories.",
|
|
32
|
+
)
|
|
33
|
+
return QdrantMemoryProvider(plugin_context=runtime_ctx)
|