@nettoolskit/memory 0.0.1-preview.1
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.
- package/LICENSE +21 -0
- package/README.md +791 -0
- package/npm/cli/ntk-memory.js +55 -0
- package/package.json +42 -0
- package/scripts/npm/postinstall.js +20 -0
- package/scripts/npm/stage-native.js +31 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 NetToolsKit
|
|
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.
|
package/README.md
ADDED
|
@@ -0,0 +1,791 @@
|
|
|
1
|
+
# NetToolsKit Memory
|
|
2
|
+
|
|
3
|
+
> Knowledge ingestion, local memory, RAG, HyDE, retrieval, context packages, and
|
|
4
|
+
> vault materialization for NetToolsKit.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Introduction
|
|
9
|
+
|
|
10
|
+
`nettoolskit-memory` is the dedicated NetToolsKit repository for memory and
|
|
11
|
+
knowledge workflows that are currently being extracted from the historical
|
|
12
|
+
`nettoolskit-copilot` umbrella workspace.
|
|
13
|
+
|
|
14
|
+
This repository owns reusable memory capabilities and integrates with the rest
|
|
15
|
+
of the NetToolsKit ecosystem through explicit contracts, manifests, APIs, and
|
|
16
|
+
generated artifacts. It does not own agent instruction policy, machine control,
|
|
17
|
+
code generation, DevOps deployment, assurance testing, or product orchestration.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Features
|
|
22
|
+
|
|
23
|
+
- Knowledge record ingestion and normalized document contracts.
|
|
24
|
+
- Chunking, deterministic embedding contracts, injectable local embedding
|
|
25
|
+
provider boundary, provider-scoped vector retrieval, graph expansion, and
|
|
26
|
+
bounded context package assembly.
|
|
27
|
+
- Memory-owned LocalFirst SQLite vector functions for deterministic semantic
|
|
28
|
+
query readiness without a native extension dependency in the default build.
|
|
29
|
+
- Typed HyDE generator contract with deterministic default generation, stable
|
|
30
|
+
generator id/version provenance, orchestrator-supplied hypothesis intake,
|
|
31
|
+
cache-key isolation, and local-first query expansion.
|
|
32
|
+
- Request-bounded reusable Memory OS recall for validated or published
|
|
33
|
+
semantic/procedural records inside context packages and query answers.
|
|
34
|
+
- Repository-local operational memory for sessions, events, artifacts, and
|
|
35
|
+
replayable recall.
|
|
36
|
+
- Typed local operational memory APIs for sessions, runs, tool calls,
|
|
37
|
+
artifacts, validations, route decisions, and selected memory-record pruning.
|
|
38
|
+
- Durable CAG/cache contracts, SQLite persistence, and automatic LocalFirst
|
|
39
|
+
reuse for retrieval results, context packages, rerank results, and
|
|
40
|
+
groundedness-linked verified answers across process boundaries.
|
|
41
|
+
- Optional feature-gated shared PostgreSQL profile with pgvector-backed vector
|
|
42
|
+
search, PostgreSQL-backed graph expansion, persistent CAG/cache reuse,
|
|
43
|
+
reusable Memory OS records, and operational-memory persistence for enterprise
|
|
44
|
+
deployments.
|
|
45
|
+
- Vault materialization for grouped Markdown knowledge records and generated
|
|
46
|
+
vault manifests.
|
|
47
|
+
- Explicit memory-engine facade for downstream command adapters and product
|
|
48
|
+
runtimes.
|
|
49
|
+
- Contract-aligned `nettoolskit.manifest.json` for service discovery by
|
|
50
|
+
NetToolsKit orchestrators and control surfaces.
|
|
51
|
+
- Local `ntk-memory` CLI commands for manifest rendering, workspace
|
|
52
|
+
materialization, vault materialization, and bounded knowledge queries.
|
|
53
|
+
- Optional caller-gated verified answer cache reuse for `ntk-memory query`
|
|
54
|
+
request files that provide a verification token and pass deterministic
|
|
55
|
+
groundedness validation.
|
|
56
|
+
- Dedicated `ntk-memory context-package` command for RAG/CAG/HyDE context
|
|
57
|
+
assembly without answer text.
|
|
58
|
+
- Hybrid Search V2 contracts for deterministic BM25-style lexical scoring,
|
|
59
|
+
normalized vector plus lexical fusion, field-match explainability, and
|
|
60
|
+
bounded context-package candidate windows.
|
|
61
|
+
- Deterministic reranker contracts with score-component explainability,
|
|
62
|
+
request-activated execution, and typed rerank-result cache keys.
|
|
63
|
+
- Contextual compression contracts that retain source-backed spans, citations,
|
|
64
|
+
source text hashes, matched query terms, and compression metrics without
|
|
65
|
+
generating answer text.
|
|
66
|
+
- Deterministic groundedness validation for caller-provided answer text against
|
|
67
|
+
retained context-package evidence, with supported terms, unsupported terms,
|
|
68
|
+
evidence matches, and machine-readable reason codes.
|
|
69
|
+
- Content-free RAG quality observability contracts for stage latency, counts,
|
|
70
|
+
cache hit/miss, scores, compression ratio, groundedness score, and bounded
|
|
71
|
+
reason codes without raw prompts, answers, snippets, or evidence text.
|
|
72
|
+
- Sanitized DET context evidence export contract, golden example, fixture, and
|
|
73
|
+
runbook for local effectiveness evidence, including DET `use_det`, `hold`,
|
|
74
|
+
and `blocked` package decisions plus sanitized metrics host/provider binding
|
|
75
|
+
without raw prompts, secrets, provider payloads, local paths, or unredacted
|
|
76
|
+
user content.
|
|
77
|
+
- Local `ntk-memory` CLI commands for operational memory write, read, and
|
|
78
|
+
prune operations.
|
|
79
|
+
- Profile-aware `ntk-memory memory-record-*` CLI commands for reusable Memory OS
|
|
80
|
+
record write, read, promotion, and prune operations.
|
|
81
|
+
- Deterministic `ntk-memory doctor` readiness checks for LocalFirst and shared
|
|
82
|
+
PostgreSQL stores, persistent CAG/cache table and indexes, round-trip cache
|
|
83
|
+
writes, query lanes, and enterprise memory-lane selection.
|
|
84
|
+
- Experimental Rust crate implementation extracted from the historical
|
|
85
|
+
`nettoolskit-copilot` knowledge foundation.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Contents
|
|
90
|
+
|
|
91
|
+
- [Introduction](#introduction)
|
|
92
|
+
- [Features](#features)
|
|
93
|
+
- [Architecture](#architecture)
|
|
94
|
+
- [Responsibility Boundary](#responsibility-boundary)
|
|
95
|
+
- [Source Extraction Map](#source-extraction-map)
|
|
96
|
+
- [Storage Model](#storage-model)
|
|
97
|
+
- [Persistent CAG Cache API](#persistent-cag-cache-api)
|
|
98
|
+
- [Local Operational Memory API](#local-operational-memory-api)
|
|
99
|
+
- [Control Plane Model](#control-plane-model)
|
|
100
|
+
- [Rust Crate](#rust-crate)
|
|
101
|
+
- [Local CLI](#local-cli)
|
|
102
|
+
- [Compatibility and Support](#compatibility-and-support)
|
|
103
|
+
- [Operations](#operations)
|
|
104
|
+
- [Planning](#planning)
|
|
105
|
+
- [Governance and Security](#governance-and-security)
|
|
106
|
+
- [Build and Tests](#build-and-tests)
|
|
107
|
+
- [Contributing](#contributing)
|
|
108
|
+
- [Dependencies](#dependencies)
|
|
109
|
+
- [References](#references)
|
|
110
|
+
- [License](#license)
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Architecture
|
|
115
|
+
|
|
116
|
+
```mermaid
|
|
117
|
+
flowchart TD
|
|
118
|
+
agent[nettoolskit-agent]
|
|
119
|
+
memory[nettoolskit-memory]
|
|
120
|
+
copilot[nettoolskit-copilot]
|
|
121
|
+
control[nettoolskit-control]
|
|
122
|
+
rust[nettoolskit-rust]
|
|
123
|
+
docs[docs/knowledge-base]
|
|
124
|
+
store[.build/knowledge/store]
|
|
125
|
+
local[.temp/context-memory]
|
|
126
|
+
vault[.deployment/artifacts/knowledge-vault]
|
|
127
|
+
|
|
128
|
+
agent -->|policy and validation rules| copilot
|
|
129
|
+
copilot -->|runtime decisions| memory
|
|
130
|
+
copilot --> control
|
|
131
|
+
memory --> rust
|
|
132
|
+
memory --> docs
|
|
133
|
+
memory --> store
|
|
134
|
+
memory --> local
|
|
135
|
+
memory --> vault
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`nettoolskit-memory` is the memory execution boundary. It consumes policy and
|
|
139
|
+
contracts from other repositories but keeps ingestion, retrieval, persistence,
|
|
140
|
+
and context-package behavior behind memory-owned APIs.
|
|
141
|
+
|
|
142
|
+
The current Rust implementation is intentionally extracted without deleting the
|
|
143
|
+
historical `nettoolskit-copilot` sources. A later compatibility-adapter PR will
|
|
144
|
+
decide when `nettoolskit-copilot` starts consuming this repository directly.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## Responsibility Boundary
|
|
149
|
+
|
|
150
|
+
| Repository | Owns |
|
|
151
|
+
| --- | --- |
|
|
152
|
+
| `nettoolskit-agent` | Instructions, prompts, governance, validation, model-routing policy, context-economy policy, and memory/RAG/HyDE usage rules. |
|
|
153
|
+
| `nettoolskit-memory` | Knowledge ingestion, chunking, embeddings, retrieval, graph expansion, HyDE, context packages, local memory, and vault materialization. |
|
|
154
|
+
| `nettoolskit-copilot` | Runtime orchestration, prompt middleware, model selection, approval coordination, and product workflow composition. |
|
|
155
|
+
| `nettoolskit-control` | Machine workers, leases, command execution, approvals, and evidence collection. |
|
|
156
|
+
| `nettoolskit-codegen` | Code generation, scaffolding, refactor planning, and architecture validation. |
|
|
157
|
+
| `nettoolskit-assurance` | Security, performance, benchmark, OpenAPI, frontend, and quality gate validation. |
|
|
158
|
+
| `nettoolskit-devops` | Docker, images, deployment, backup, observability, proxy, and operations. |
|
|
159
|
+
| `nettoolskit-rust` | Generic Rust core, contracts, CLI, observability, adapters, validation, and specification foundations. |
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Source Extraction Map
|
|
164
|
+
|
|
165
|
+
Initial source material comes from `nettoolskit-copilot`:
|
|
166
|
+
|
|
167
|
+
| Current source | Target ownership |
|
|
168
|
+
| --- | --- |
|
|
169
|
+
| `crates/knowledge` | Move to `nettoolskit-memory` as the primary knowledge and retrieval crate. |
|
|
170
|
+
| `crates/memory/engine` | Replace with `nettoolskit_memory::engine` as the memory facade. |
|
|
171
|
+
| `crates/control/runtime/src/continuity/local_context.rs` | Split memory-owned persistence/retrieval from runtime command orchestration. |
|
|
172
|
+
| `crates/control/runtime/src/maintenance/prune_local_memory.rs` | Move local memory retention logic to `nettoolskit-memory`; keep runtime command wiring in the caller. |
|
|
173
|
+
| `docs/knowledge-base/**` | Keep durable authored knowledge records versioned in the owning product repository; memory provides validation and processing APIs. |
|
|
174
|
+
|
|
175
|
+
Do not delete or deprecate the existing `nettoolskit-copilot` sources until the
|
|
176
|
+
new memory crate has mirrored tests, a compatibility adapter, and a confirmed
|
|
177
|
+
consumer integration path.
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## Storage Model
|
|
182
|
+
|
|
183
|
+
Generated stores are rebuildable runtime artifacts and must not be committed.
|
|
184
|
+
|
|
185
|
+
| Store | Purpose |
|
|
186
|
+
| --- | --- |
|
|
187
|
+
| `.build/knowledge/store/knowledge.db` | Rebuildable knowledge store for ingestion, vector retrieval, durable graph state, persistent CAG/cache entries, and materialized workspace state. |
|
|
188
|
+
| Shared PostgreSQL schema | External shared store selected only through `SharedPostgresqlSettings` and a connection-string environment variable. |
|
|
189
|
+
| `.temp/context-memory/context.db` | Rebuildable local operational memory for sessions, events, artifacts, and recall. |
|
|
190
|
+
| `.deployment/artifacts/knowledge-vault/**` | Generated vault and validation artifacts for review or publication. |
|
|
191
|
+
| `docs/knowledge-base/**` | Durable authored knowledge records owned by the product or domain repository. |
|
|
192
|
+
|
|
193
|
+
The default Rust crate writes local operational-memory, graph, and persistent
|
|
194
|
+
CAG/cache API data to the repository-local SQLite schema under
|
|
195
|
+
`.build/knowledge/store/knowledge.db`. The optional `shared-postgresql` Cargo
|
|
196
|
+
feature adds `SharedPostgresqlSettings`, `PostgresVectorRepository`,
|
|
197
|
+
`PostgresGraphRepository`, `PostgresPersistentCacheBackend`,
|
|
198
|
+
`PostgresMemoryRecordBackend`, and `PostgresOperationalMemoryBackend` for
|
|
199
|
+
explicit shared deployments. Shared PostgreSQL configuration names the
|
|
200
|
+
environment variable that contains the connection string; the value itself must
|
|
201
|
+
never be committed, logged, or emitted in artifacts. Shared operational memory
|
|
202
|
+
for sessions, runs, tool calls, artifacts, validations, and route decisions uses
|
|
203
|
+
the same `persistence_profile`/`shared_postgresql` request shape in the
|
|
204
|
+
contract pack. Legacy
|
|
205
|
+
`.temp/context-memory/context.db` remains listed as extraction source material
|
|
206
|
+
until downstream runtime adapters move to the memory-owned API.
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Persistent CAG Cache API
|
|
211
|
+
|
|
212
|
+
The persistent cache API is the durable boundary for reusable CAG state. It
|
|
213
|
+
stores typed cache entries as JSON payloads with deterministic keys, stable
|
|
214
|
+
payload hashes, creation timestamps, optional expiration timestamps, and schema
|
|
215
|
+
versions.
|
|
216
|
+
|
|
217
|
+
The API exposes:
|
|
218
|
+
|
|
219
|
+
| Contract | Purpose |
|
|
220
|
+
| --- | --- |
|
|
221
|
+
| `PersistentCacheEntry` | Validated durable cache row for retrieval results, context packages, or verified idempotent results. |
|
|
222
|
+
| `PersistentCachePolicy` | Materialized-workspace policy that enables/disables durable cache kinds and sets per-kind TTLs. |
|
|
223
|
+
| `PersistentCacheReadRequest` | Reads one cache entry and treats expired rows as misses unless `include_expired` is explicit. |
|
|
224
|
+
| `PersistentCachePruneRequest` | Selects entries by kind, expiration, schema version, or payload hash and supports dry-run mode. |
|
|
225
|
+
| `persist_persistent_cache_entry` | Upserts one validated cache entry into the repository-local SQLite store. |
|
|
226
|
+
| `read_persistent_cache_entry` | Reads one cache entry through the TTL-aware typed read path. |
|
|
227
|
+
| `prune_persistent_cache_entries` | Deletes or previews selected cache rows without exposing a shell-like deletion surface. |
|
|
228
|
+
| `probe_persistent_cache_readiness` | Validates the persistent-cache table, required indexes, TTL-aware reads, and doctor-owned write/read/prune round-trip. |
|
|
229
|
+
|
|
230
|
+
This API does not decide which model, prompt, or orchestration lane should use
|
|
231
|
+
a cached value. That decision remains in `nettoolskit-copilot`; this repository
|
|
232
|
+
owns the deterministic storage and validation surface. Within
|
|
233
|
+
`nettoolskit-memory`, materialized workspaces automatically read and write
|
|
234
|
+
durable cache entries when the selected repository resolver provides a
|
|
235
|
+
`PersistentCacheBackend`. LocalFirst attaches the SQLite backend by default;
|
|
236
|
+
the feature-gated shared PostgreSQL profile attaches
|
|
237
|
+
`PostgresPersistentCacheBackend` when explicit safe settings are provided. The
|
|
238
|
+
same resolver selects the reusable Memory OS backend, so materialization can
|
|
239
|
+
publish and recall reusable memory records through SQLite or shared PostgreSQL
|
|
240
|
+
without changing caller code. Both profiles use a workspace content fingerprint
|
|
241
|
+
to avoid stale reuse after source changes.
|
|
242
|
+
|
|
243
|
+
Automatic LocalFirst cache writes use kind-specific TTLs by default:
|
|
244
|
+
|
|
245
|
+
| Cache kind | Default TTL |
|
|
246
|
+
| --- | --- |
|
|
247
|
+
| `query_embedding` | 21,600 seconds |
|
|
248
|
+
| `retrieval_result` | 21,600 seconds |
|
|
249
|
+
| `rerank_result` | 21,600 seconds |
|
|
250
|
+
| `context_package` | 86,400 seconds |
|
|
251
|
+
| `verified_idempotent_result` | 604,800 seconds |
|
|
252
|
+
|
|
253
|
+
`PersistentCachePolicy` can disable individual durable cache kinds or set a
|
|
254
|
+
custom positive TTL. A `ttl_seconds` value of `null` keeps that kind enabled
|
|
255
|
+
without an automatic expiration timestamp. Manual `ntk-memory cache-write`
|
|
256
|
+
requests remain explicit `PersistentCacheEntry` payloads and can still provide
|
|
257
|
+
their own `expires_at_unix_seconds` per entry.
|
|
258
|
+
|
|
259
|
+
Retrieval and context-package cache keys include an explicit enterprise
|
|
260
|
+
filter-scope fingerprint. Tenant, access role, document version, domain,
|
|
261
|
+
publication date windows, content root, source path, language, document kind,
|
|
262
|
+
and lexical shortlist filters therefore cannot reuse cache entries across
|
|
263
|
+
different retrieval scopes. Context-package cache keys also include the HyDE
|
|
264
|
+
generator id and version when HyDE mode is active, the contextual compression
|
|
265
|
+
profile scope when compression is enabled, and the rerank profile plus result
|
|
266
|
+
budget when reranking is enabled, so generator, compression, or rerank changes
|
|
267
|
+
do not reuse stale packages from a different evidence shape.
|
|
268
|
+
|
|
269
|
+
Query embedding cache keys are narrower by design. They include provider id,
|
|
270
|
+
provider version, vector dimension, and a query text hash, but never the raw
|
|
271
|
+
query text. This allows the same query vector to be reused across different
|
|
272
|
+
tenant/filter/budget scopes while retrieval-result cache entries remain scoped
|
|
273
|
+
to the full request.
|
|
274
|
+
|
|
275
|
+
Rerank-result cache keys include reranker id, reranker version, profile id,
|
|
276
|
+
query text, result budget, and a fingerprint of the candidate window. The
|
|
277
|
+
deterministic reranker runs when `KnowledgeQueryRequestInput` sets
|
|
278
|
+
`enable_rerank: true` with a positive `max_rerank_hits`; selecting a
|
|
279
|
+
model-assisted reranker or fallback policy remains the responsibility of the
|
|
280
|
+
calling orchestrator.
|
|
281
|
+
|
|
282
|
+
Verified answer reuse is always caller-gated. The memory service stores and
|
|
283
|
+
reuses verified idempotent answer text only when the query request includes a
|
|
284
|
+
non-empty `verification_token` and deterministic groundedness validation accepts
|
|
285
|
+
the answer against the retained context package. Verified answer cache keys also
|
|
286
|
+
include `answer_generation_scope`: the safe provider/model/model version surface
|
|
287
|
+
that produced the answer candidate. This prevents verified answers generated by
|
|
288
|
+
different providers, models, or model versions from reusing the same cache row.
|
|
289
|
+
The durable payload is a `VerifiedAnswerCacheEntry` with answer hash,
|
|
290
|
+
context-package hash, verification-token fingerprint, answer generation scope,
|
|
291
|
+
and the accepted groundedness result. Provider answers produced outside memory
|
|
292
|
+
must be persisted through `ntk-memory verified-answer-cache-write`, which
|
|
293
|
+
rebuilds the query context and computes Memory-owned cache keys and hashes
|
|
294
|
+
instead of asking callers to submit low-level `PersistentCacheEntry` rows. The
|
|
295
|
+
command output contains only cache metadata and hashes; it does not echo answer
|
|
296
|
+
text or verification tokens. Deciding when to call providers, retry, degrade, or
|
|
297
|
+
expose cached answers remains in the calling orchestrator.
|
|
298
|
+
|
|
299
|
+
Provider and model identifiers in `answer_generation_scope` are cache scope
|
|
300
|
+
tokens, not configuration channels. They must be stable, non-secret identifiers
|
|
301
|
+
and must not contain credentials, bearer tokens, prompts, answer text,
|
|
302
|
+
transcripts, request headers, customer data, local filesystem paths, database
|
|
303
|
+
URLs, or other environment-specific secrets.
|
|
304
|
+
|
|
305
|
+
`ntk-memory doctor` uses a controlled persistent-cache probe to verify the
|
|
306
|
+
table, indexes, TTL miss behavior, and write/read/prune behavior. The probe
|
|
307
|
+
removes its doctor-owned row before reporting success and does not prune
|
|
308
|
+
runtime cache rows.
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Local Operational Memory API
|
|
313
|
+
|
|
314
|
+
The local operational memory API is adapter-facing and deterministic. It writes
|
|
315
|
+
sessions, runs, tool calls, artifacts, validations, and route decisions through
|
|
316
|
+
`OperationalMemoryWriteBatch`. Batch writes are atomic: if one child row fails,
|
|
317
|
+
the full write is rolled back.
|
|
318
|
+
|
|
319
|
+
`OperationalMemoryReadRequest` applies session and run filters as an
|
|
320
|
+
intersection. Session filters constrain matching runs and child rows; run
|
|
321
|
+
filters constrain parent sessions and child rows. Route decisions are filtered
|
|
322
|
+
independently by `route_kind`.
|
|
323
|
+
|
|
324
|
+
Operational payloads must be sanitized before persistence. The crate rejects
|
|
325
|
+
null payloads, artifact paths outside repository-relative form, common local
|
|
326
|
+
path markers, and secret-like token markers. Runtime adapters must summarize
|
|
327
|
+
large logs before calling this API.
|
|
328
|
+
|
|
329
|
+
`MemoryRecordPruneRequest` requires at least one explicit selection filter and
|
|
330
|
+
supports dry-run mode. Non-dry-run prune deletes selected memory records and
|
|
331
|
+
their source-memory promotion rows in one transaction.
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## Control Plane Model
|
|
336
|
+
|
|
337
|
+
`nettoolskit-memory` exposes deterministic memory capabilities through typed
|
|
338
|
+
contracts and command-ready APIs. It does not decide which model to use, when to
|
|
339
|
+
call an LLM, which worker executes a task, or whether an approval gate passes.
|
|
340
|
+
|
|
341
|
+
Runtime orchestration belongs to `nettoolskit-copilot`. Machine execution
|
|
342
|
+
belongs to `nettoolskit-control`. Generic CLI building blocks belong to
|
|
343
|
+
`nettoolskit-rust`.
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## Rust Crate
|
|
348
|
+
|
|
349
|
+
This repository uses the product-repository single-crate layout.
|
|
350
|
+
|
|
351
|
+
| Path | Package | Responsibility |
|
|
352
|
+
| --- | --- | --- |
|
|
353
|
+
| `src/**` | `nettoolskit-memory` | Knowledge ingestion, retrieval, context packages, local memory, and vault materialization. |
|
|
354
|
+
| `src/engine/**` | `nettoolskit-memory` | Grouped public facade for downstream adapters and product runtimes. |
|
|
355
|
+
| `src/local/**` | `nettoolskit-memory` | Local operational memory contracts for sessions, runs, artifacts, validations, route decisions, and prune requests. |
|
|
356
|
+
| `tests/**` | `nettoolskit-memory` | Mirrored integration tests for the source modules. |
|
|
357
|
+
|
|
358
|
+
Cargo build output is configured under `.build/target` through
|
|
359
|
+
`.cargo/config.toml`.
|
|
360
|
+
|
|
361
|
+
The crate exposes the typed HyDE generator boundary through `HydeGenerator`,
|
|
362
|
+
`DeterministicHydeGenerator`, `SuppliedHydeGenerator`, `HydeHypothesis`, and
|
|
363
|
+
`SuppliedHydeHypothesis`, with generator id/version provenance retained in
|
|
364
|
+
context package output. Supplied HyDE is a data-only contract for external
|
|
365
|
+
orchestrators such as `nettoolskit-copilot`; memory validates the query match
|
|
366
|
+
and provenance fields, then uses the hypothesis for retrieval and cache scope.
|
|
367
|
+
The cache scope preserves the external generator id/version and adds a
|
|
368
|
+
hypothesis-text fingerprint so different supplied hypotheses cannot reuse the
|
|
369
|
+
same context package accidentally. Prompt templates, model routing,
|
|
370
|
+
credentials, retries, and orchestration policy remain outside this repository.
|
|
371
|
+
|
|
372
|
+
The default local orchestrator uses `HashBucketEmbeddingProvider` for
|
|
373
|
+
deterministic development and test runs. Downstream Rust consumers can inject a
|
|
374
|
+
custom local `EmbeddingProvider` through `LocalKnowledgeOrchestrator` while
|
|
375
|
+
keeping provider id/version provenance in embeddings, retrieval explanations,
|
|
376
|
+
and cache keys. This crate does not implement network embedding providers or
|
|
377
|
+
own provider secrets.
|
|
378
|
+
|
|
379
|
+
---
|
|
380
|
+
|
|
381
|
+
## Local CLI
|
|
382
|
+
|
|
383
|
+
The repository builds a local-process binary named `ntk-memory`. It is the
|
|
384
|
+
preferred adapter boundary for product orchestrators that should call memory
|
|
385
|
+
capabilities without linking to memory internals.
|
|
386
|
+
|
|
387
|
+
Supported commands:
|
|
388
|
+
|
|
389
|
+
| Command | Purpose |
|
|
390
|
+
| --- | --- |
|
|
391
|
+
| `ntk-memory manifest [--output <path>]` | Render the service manifest as deterministic JSON. |
|
|
392
|
+
| `ntk-memory materialize --request <path> [--output <path>]` | Ingest and index a bounded workspace through the request-selected memory persistence profile. |
|
|
393
|
+
| `ntk-memory query --request <path> [--output <path>]` | Run vector retrieval, graph expansion, HyDE, reusable memory recall, context package assembly, profile-backed persistence, and optional caller-gated verified answer reuse. |
|
|
394
|
+
| `ntk-memory context-package --request <path> [--output <path>]` | Assemble a bounded context package with retrieval evidence, reusable memory recall, and profile-backed cache metadata without answer text. |
|
|
395
|
+
| `ntk-memory groundedness-validate --request <path> [--output <path>]` | Validate caller-provided answer text against retained context-package evidence without model routing or answer generation. |
|
|
396
|
+
| `ntk-memory verified-answer-cache-write --request <path> [--output <path>]` | Rebuild the query context, validate a provider answer, and persist verified answer cache state with Memory-owned keys and hashes. |
|
|
397
|
+
| `ntk-memory vault-materialize --request <path> [--output <path>]` | Materialize grouped Markdown knowledge vault records and a vault manifest. |
|
|
398
|
+
| `ntk-memory doctor --repo-root <path> [--request <path>] [--output <path>]` | Report LocalFirst or request-selected shared PostgreSQL runtime readiness for enterprise RAG/CAG/HyDE/context/verified-cache/operational-memory lanes. |
|
|
399
|
+
| `ntk-memory cache-write --repo-root <path> --request <path> [--output <path>]` | Persist one durable CAG/cache entry. |
|
|
400
|
+
| `ntk-memory cache-read --repo-root <path> --request <path> [--output <path>]` | Read one durable CAG/cache entry with TTL-aware miss semantics. |
|
|
401
|
+
| `ntk-memory cache-prune --repo-root <path> --request <path> [--output <path>]` | Prune selected durable CAG/cache entries with explicit filters and dry-run support. |
|
|
402
|
+
| `ntk-memory local-write --repo-root <path> --request <path> [--output <path>]` | Persist a repository-local operational memory write batch. |
|
|
403
|
+
| `ntk-memory local-read --repo-root <path> --request <path> [--output <path>]` | Read repository-local operational memory rows with deterministic filters. |
|
|
404
|
+
| `scripts/operations/write-det-local-first-use-memory.ps1` | Write `.deployment/artifacts/memory/det-local-first-use-write.json` for DET `runtime-wrapper` readiness. |
|
|
405
|
+
| `ntk-memory local-prune --repo-root <path> --request <path> [--output <path>]` | Prune selected Memory OS records with explicit filters and dry-run support. |
|
|
406
|
+
| `ntk-memory memory-record-write --repo-root <path> --request <path> [--output <path>]` | Persist validated reusable Memory OS records through the request-selected profile. |
|
|
407
|
+
| `ntk-memory memory-record-read --repo-root <path> --request <path> [--output <path>]` | Read reusable Memory OS records and optional promotion metadata through the request-selected profile. |
|
|
408
|
+
| `ntk-memory memory-record-promote --repo-root <path> --request <path> [--output <path>]` | Persist an explicit Memory OS promotion and its target record through the request-selected profile. |
|
|
409
|
+
| `ntk-memory memory-record-prune --repo-root <path> --request <path> [--output <path>]` | Prune selected Memory OS records through the public profile-aware record adapter surface. |
|
|
410
|
+
|
|
411
|
+
Request files use the Rust API payloads `KnowledgeWorkspaceRequestInput`,
|
|
412
|
+
`KnowledgeQueryRequestInput`, and `KnowledgeVaultBuildRequestInput`. The
|
|
413
|
+
`query` command returns answer text plus the context package; `context-package`
|
|
414
|
+
returns only retrieval package data and cache metadata. `vault-materialize`
|
|
415
|
+
uses `output_root` from the request JSON as the Markdown vault destination;
|
|
416
|
+
the CLI `--output` flag is only the machine-readable JSON report destination.
|
|
417
|
+
Outputs are machine-readable JSON. When `--output` is omitted, the command
|
|
418
|
+
writes JSON to stdout.
|
|
419
|
+
|
|
420
|
+
Workspace-backed commands default to `local_first`. Callers can select
|
|
421
|
+
`shared_postgresql` by adding `persistence_profile: "shared_postgresql"` and a
|
|
422
|
+
secret-safe `shared_postgresql` settings object to the workspace request. The
|
|
423
|
+
settings object names the environment variable containing the connection string
|
|
424
|
+
and never carries the secret value itself. If the optional
|
|
425
|
+
`shared-postgresql` Cargo feature or required environment variable is missing,
|
|
426
|
+
the command fails closed with a sanitized profile/readiness error and does not
|
|
427
|
+
bootstrap the repository-local SQLite store.
|
|
428
|
+
|
|
429
|
+
`KnowledgeQueryRequestInput` can opt into reusable Memory OS recall with
|
|
430
|
+
`enable_reusable_memory_recall: true` and a positive
|
|
431
|
+
`max_reusable_memory_hits` budget. When enabled, local-first materialization
|
|
432
|
+
loads validated or published `semantic` and `procedural` records from
|
|
433
|
+
`memory_items`; recalled records appear as `memory_record` snippets, evidence,
|
|
434
|
+
and the optional `reusable_memory_recall` output block. The cache key includes
|
|
435
|
+
a reusable-memory scope fingerprint so changed memory records cannot reuse a
|
|
436
|
+
stale context package.
|
|
437
|
+
|
|
438
|
+
`KnowledgeQueryRequestInput` can also apply enterprise retrieval scope filters:
|
|
439
|
+
`tenant_id`, `access_roles`, `document_version`, `domain`,
|
|
440
|
+
`min_published_at_unix_seconds`, and `max_published_at_unix_seconds`. These
|
|
441
|
+
filters are optional for compatibility, but when a caller supplies them memory
|
|
442
|
+
fails closed: a chunk without matching metadata is excluded from lexical
|
|
443
|
+
prefiltering, vector retrieval, context packages, and cache reuse.
|
|
444
|
+
|
|
445
|
+
When `enable_lexical_prefilter` is true with a positive `max_lexical_hits`,
|
|
446
|
+
memory scores the lexical corpus with the `LexicalScoringProfile` contract and
|
|
447
|
+
applies the same enterprise filters before scoring. Context-package assembly
|
|
448
|
+
then uses `HybridFusionProfile` to normalize and fuse vector and lexical
|
|
449
|
+
scores, emitting `vector_score`, `lexical_score`, `fusion_score`, ranking
|
|
450
|
+
stages, matched lexical fields, and the fusion profile in retrieval
|
|
451
|
+
explanations. Default behavior remains semantic-only unless the request enables
|
|
452
|
+
lexical prefiltering.
|
|
453
|
+
|
|
454
|
+
Contextual compression is exposed as a memory-owned package assembly primitive.
|
|
455
|
+
When a caller supplies `context_compression_profile`, memory replaces package
|
|
456
|
+
snippets with retained source spans and emits `compression.retained_spans` plus
|
|
457
|
+
`compression.metrics`. The retained text is copied from source snippets only;
|
|
458
|
+
model routing, deciding whether compression is worth the latency/cost tradeoff,
|
|
459
|
+
and answer generation remain caller responsibilities.
|
|
460
|
+
|
|
461
|
+
Deterministic reranking is request-activated. When `enable_rerank` is true,
|
|
462
|
+
memory applies `rerank_profile` or the default deterministic profile after
|
|
463
|
+
semantic or hybrid retrieval, caps output with `max_rerank_hits`, emits the
|
|
464
|
+
optional `context_package.rerank` block, and updates retained snippets and
|
|
465
|
+
evidence ordering before optional compression.
|
|
466
|
+
|
|
467
|
+
Groundedness validation is exposed as `GroundednessValidationRequest`,
|
|
468
|
+
`GroundednessValidationResult`, and `ntk-memory groundedness-validate`. The
|
|
469
|
+
validator compares caller-provided answer text against retained context-package
|
|
470
|
+
snippets or compression spans, emits supported and unsupported terms plus
|
|
471
|
+
reason codes, and never calls an LLM. Retry, degrade, or final-answer policy
|
|
472
|
+
remains owned by the caller.
|
|
473
|
+
|
|
474
|
+
RAG quality observability is exposed as `RagQualityReport`,
|
|
475
|
+
`RagQualityStageMetric`, and the `rag-quality-report` contract. Reports are
|
|
476
|
+
intentionally content-free: they use hashes for request, tenant, and query
|
|
477
|
+
scope and only store stage status, latency, counts, cache hit/miss, normalized
|
|
478
|
+
scores, compression ratio, token/cost counters, profile ids, and bounded reason
|
|
479
|
+
codes. Prompt text, answer text, HyDE text, snippets, retained spans, evidence
|
|
480
|
+
text, workstation paths, and secret values must stay out of these reports.
|
|
481
|
+
`query` and `context-package` attach `quality_report` only when
|
|
482
|
+
`emit_quality_report` is true.
|
|
483
|
+
|
|
484
|
+
DET context evidence export is represented by `det-context-evidence-export`.
|
|
485
|
+
It is a pending contract and fixture for DET, Harness, and Analytics local
|
|
486
|
+
effectiveness evidence derived from existing context-package, quality-report,
|
|
487
|
+
groundedness, and cache metadata. The export is content-free by contract and
|
|
488
|
+
uses only hashes, counts, booleans, bounded reason codes, safe identifiers, and
|
|
489
|
+
normalized scores. It must not include prompts, query text, snippets, retained
|
|
490
|
+
spans, provider payloads, answer text, secrets, local paths, or unredacted user
|
|
491
|
+
content. The optional `effectiveness.det_local_effectiveness_package` object
|
|
492
|
+
models DET's local effectiveness bridge with a `use_det`, `hold`, or `blocked`
|
|
493
|
+
decision and sanitized metrics binding where the host is hashed and the metrics
|
|
494
|
+
provider is represented only by safe identifiers.
|
|
495
|
+
|
|
496
|
+
For LocalFirst workspaces, query embeddings, retrieval results, context
|
|
497
|
+
packages, rerank results, and verified answers can reuse durable cache rows
|
|
498
|
+
from previous processes. Public response status fields currently expose
|
|
499
|
+
`cache_status.retrieval_result_cache_hit`,
|
|
500
|
+
`cache_status.context_package_cache_hit`, and
|
|
501
|
+
`cache_status.verified_idempotent_result_cache_hit` may reflect durable hits
|
|
502
|
+
from a previous process. Verified answer reuse still requires an explicit
|
|
503
|
+
`verification_token` in the `KnowledgeQueryRequestInput` JSON plus a validated
|
|
504
|
+
groundedness-linked cache payload, so unverified or unsupported `query` calls
|
|
505
|
+
never reuse answer text across processes.
|
|
506
|
+
|
|
507
|
+
CLI query and context-package commands use the deterministic HyDE generator by
|
|
508
|
+
default and include HyDE generator provenance in returned context metadata when
|
|
509
|
+
HyDE mode is active. Request JSON can instead provide
|
|
510
|
+
`supplied_hyde_hypothesis` with `query_text`, `hypothesis_text`,
|
|
511
|
+
`generator_id`, `generator_version`, and `provenance`. Memory rejects blank
|
|
512
|
+
fields, rejects query mismatches, and accepts supplied HyDE only for
|
|
513
|
+
HyDE-assisted retrieval.
|
|
514
|
+
|
|
515
|
+
Operational-memory commands keep payload hygiene fail-closed for local paths
|
|
516
|
+
and secret-like values before any write reaches persistence. Their current
|
|
517
|
+
LocalFirst request shape remains valid; the contract pack also publishes
|
|
518
|
+
shared PostgreSQL examples for `local-write` and `local-read` using
|
|
519
|
+
`persistence_profile: "shared_postgresql"` plus secret-safe
|
|
520
|
+
`shared_postgresql` settings.
|
|
521
|
+
|
|
522
|
+
Persistent-cache command request files use the Rust API payloads
|
|
523
|
+
`PersistentCacheEntry`, `PersistentCacheReadRequest`, and
|
|
524
|
+
`PersistentCachePruneRequest`. `cache-write` returns the persisted entry
|
|
525
|
+
identity, and `cache-read` returns `null` when an entry does not exist or is
|
|
526
|
+
expired and `include_expired` is false.
|
|
527
|
+
|
|
528
|
+
Verified provider answer cache writes use
|
|
529
|
+
`VerifiedAnswerCacheWriteCommandRequest`, which wraps the original
|
|
530
|
+
`KnowledgeQueryRequestInput`, provider `answer_text`, and
|
|
531
|
+
`answer_generation_scope` with provider/model/model version identifiers. The
|
|
532
|
+
nested query must include `verification_token`; if it also includes
|
|
533
|
+
`query.answer_generation_scope`, the two scopes must match. Memory rebuilds the
|
|
534
|
+
context package, validates groundedness, writes the provider/model/model-version
|
|
535
|
+
scoped verified cache row, and returns `VerifiedAnswerCacheWriteResult` with
|
|
536
|
+
only cache metadata and hashes.
|
|
537
|
+
|
|
538
|
+
Operational command request files use the Rust API payloads
|
|
539
|
+
`OperationalMemoryWriteBatch`, `OperationalMemoryReadRequest`, and
|
|
540
|
+
`MemoryRecordPruneRequest`. The operational-memory schemas accept both the
|
|
541
|
+
current LocalFirst shape and the profile-aware shared PostgreSQL shape so
|
|
542
|
+
callers can prepare requests without changing command names.
|
|
543
|
+
|
|
544
|
+
### Adapter Contract Pack
|
|
545
|
+
|
|
546
|
+
Versioned adapter contracts live under [contracts](contracts/README.md).
|
|
547
|
+
The pack publishes JSON schemas in `contracts/schemas/v1` and sanitized golden
|
|
548
|
+
examples in `contracts/examples/v1` for query, context-package, supplied HyDE,
|
|
549
|
+
doctor, RAG quality reports, DET context evidence exports, persistent cache,
|
|
550
|
+
reusable memory records, local operational memory, and CLI error envelopes.
|
|
551
|
+
`nettoolskit.manifest.json` references these files through its `contracts`
|
|
552
|
+
array so orchestrators can discover request and response shapes without
|
|
553
|
+
linking to memory internals.
|
|
554
|
+
|
|
555
|
+
Consumers should call `ntk-memory doctor --repo-root <path>` before expensive
|
|
556
|
+
query paths, or `ntk-memory doctor --repo-root <path> --request <path>` when
|
|
557
|
+
checking a request-selected shared PostgreSQL profile. They should then call
|
|
558
|
+
`ntk-memory query` or `ntk-memory context-package` with request JSON that
|
|
559
|
+
matches the published schema. Runtime outputs, stdout, stderr, and reports
|
|
560
|
+
should be stored as harness evidence instead of reading the SQLite or
|
|
561
|
+
PostgreSQL store directly.
|
|
562
|
+
|
|
563
|
+
`doctor` is designed for orchestrators and operators. It requires an explicit
|
|
564
|
+
repository root. Without a request file it initializes the real
|
|
565
|
+
`.build/knowledge/store/knowledge.db` store, validates persistent-cache
|
|
566
|
+
table/index/TTL/prune readiness, registers the Memory-owned SQLite vector
|
|
567
|
+
function lane, and returns a stable LocalFirst readiness report. With a
|
|
568
|
+
`memory-doctor-request` file that selects `shared_postgresql`, it validates only
|
|
569
|
+
secret-safe settings, probes shared PostgreSQL pgvector, persistent-cache, and
|
|
570
|
+
operational-memory readiness, and does not bootstrap the LocalFirst SQLite
|
|
571
|
+
store. Shared PostgreSQL readiness failures are reported as `degraded` JSON
|
|
572
|
+
with exit code zero so the caller can decide whether to fail, retry, or fall
|
|
573
|
+
back before running an expensive query path.
|
|
574
|
+
|
|
575
|
+
### Doctor Readiness JSON
|
|
576
|
+
|
|
577
|
+
The readiness report is intentionally repo-relative and safe for generated
|
|
578
|
+
artifacts. It does not expose workstation absolute paths. The current schema
|
|
579
|
+
includes:
|
|
580
|
+
|
|
581
|
+
| Field | Purpose |
|
|
582
|
+
| --- | --- |
|
|
583
|
+
| `schemaVersion` | Readiness report contract version. |
|
|
584
|
+
| `service` | Memory service name, kind, version, manifest schema, and binary name. |
|
|
585
|
+
| `scope` | Repo-relative scope and effective persistence profile. |
|
|
586
|
+
| `store` | Profile backend readiness. LocalFirst reports `.build/knowledge/store`; shared PostgreSQL reports the safe `shared_postgresql` backend token. |
|
|
587
|
+
| `sqlite` | SQLite engine version and LocalFirst vector semantic query capability. |
|
|
588
|
+
| `sharedPostgresql` | Optional shared PostgreSQL readiness metadata containing only env-var name, schema, application name, and readiness state. |
|
|
589
|
+
| `capabilities` | Capability readiness states for ingest, query, context package, RAG quality report, persistent cache, and local memory. |
|
|
590
|
+
| `readiness` | Enterprise lane matrix for `rag`, `cag`, `hyde_assisted`, `context_package`, `verified_answer_cache`, `operational_memory`, and `quality_observability`, including required and degraded check ids. |
|
|
591
|
+
| `checks` | Ordered deterministic checks with `blocking` or `degrading` severity, including persistent-cache table, index, TTL, and round-trip checks. |
|
|
592
|
+
| `summary` | Aggregated ready/degraded flags and failed check IDs. |
|
|
593
|
+
|
|
594
|
+
Readiness lane status uses a strict machine contract:
|
|
595
|
+
|
|
596
|
+
- `ready` means every required check for that lane passed.
|
|
597
|
+
- `degraded` means the lane can still run through a local-first fallback, but
|
|
598
|
+
the caller should inspect `degradedCheckIds` before selecting it.
|
|
599
|
+
- `unavailable` means the orchestrator must not select that lane.
|
|
600
|
+
|
|
601
|
+
`requiredCheckIds` lists the checks that control a lane. `degradedCheckIds`
|
|
602
|
+
must be a subset of those required checks and names the failed checks from the
|
|
603
|
+
same report.
|
|
604
|
+
|
|
605
|
+
---
|
|
606
|
+
|
|
607
|
+
## Compatibility and Support
|
|
608
|
+
|
|
609
|
+
The initial compatibility target is the existing implementation in
|
|
610
|
+
`nettoolskit-copilot`. Extraction must preserve the current command and runtime
|
|
611
|
+
behavior until downstream consumers are migrated.
|
|
612
|
+
|
|
613
|
+
The current crate starts from the existing `nettoolskit-copilot` knowledge
|
|
614
|
+
foundation and keeps the same deterministic behavior while the ecosystem moves
|
|
615
|
+
to explicit memory-owned APIs.
|
|
616
|
+
|
|
617
|
+
`build_hyde_hypothesis` remains backward-compatible for existing callers while
|
|
618
|
+
new integrations can attach a typed local `HydeGenerator`.
|
|
619
|
+
|
|
620
|
+
Downstream consumers should prefer `nettoolskit_memory::engine` for new adapter
|
|
621
|
+
work. The facade keeps grouped surfaces for contracts, persistence, retrieval,
|
|
622
|
+
orchestration, context packages, vault materialization, and authored knowledge
|
|
623
|
+
records without exposing runtime orchestration policy.
|
|
624
|
+
|
|
625
|
+
Embedding provider selection belongs to the calling product runtime. This
|
|
626
|
+
repository owns the deterministic provider contract and local execution wiring;
|
|
627
|
+
external provider implementations, credential resolution, and model routing
|
|
628
|
+
belong outside `nettoolskit-memory`.
|
|
629
|
+
|
|
630
|
+
The local-first SQLite query path is capability-gated. Materialization
|
|
631
|
+
initializes the repository-local store with bundled SQLite and registers
|
|
632
|
+
deterministic Memory-owned vector SQL functions on each opened knowledge-store
|
|
633
|
+
connection. Operators and orchestrators should call `ntk-memory doctor
|
|
634
|
+
--repo-root <path>` before invoking semantic query workloads.
|
|
635
|
+
Vector retrieval is scoped by `provider_id` and `provider_version`, so multiple
|
|
636
|
+
same-dimension embeddings for the same chunk can coexist without cross-provider
|
|
637
|
+
or cross-version result contamination. Verified answer reuse is separately
|
|
638
|
+
scoped by `answer_generation_scope.provider_id`, `.model_id`, and
|
|
639
|
+
`.model_version`, so generated answers are never reused across provider/model
|
|
640
|
+
surfaces.
|
|
641
|
+
|
|
642
|
+
`SemanticRetriever::query_with_cache` first checks the retrieval-result cache.
|
|
643
|
+
On retrieval-result misses, it resolves the query vector through the
|
|
644
|
+
`query_embedding` cache before calling the embedding provider. Query embedding
|
|
645
|
+
entries store provider identity, dimension, query hash, vector, and a stable
|
|
646
|
+
embedding cache key only.
|
|
647
|
+
|
|
648
|
+
Automatic persistent cache reuse is selected through the repository resolver.
|
|
649
|
+
LocalFirst uses the repository-local SQLite backend. Shared PostgreSQL uses the
|
|
650
|
+
feature-gated `PostgresPersistentCacheBackend` when callers provide
|
|
651
|
+
secret-safe shared settings. Custom in-memory repository resolvers remain
|
|
652
|
+
SQLite-free unless they explicitly attach a persistent-cache backend.
|
|
653
|
+
|
|
654
|
+
Reusable Memory OS record persistence is selected through the same resolver.
|
|
655
|
+
LocalFirst uses `SqliteMemoryRecordBackend`; shared PostgreSQL uses
|
|
656
|
+
`PostgresMemoryRecordBackend` and stores `memory_items` plus
|
|
657
|
+
`memory_promotions` as validated JSONB payloads with indexed filter columns.
|
|
658
|
+
The `memory-record-*` command requests accept the same
|
|
659
|
+
`persistence_profile`/`shared_postgresql` shape and fail closed when shared
|
|
660
|
+
settings are incomplete or the Cargo feature is unavailable.
|
|
661
|
+
|
|
662
|
+
Operational-memory `local-write` and `local-read` contracts accept the same
|
|
663
|
+
profile/settings shape and route through `SqliteOperationalMemoryBackend` or
|
|
664
|
+
`PostgresOperationalMemoryBackend`. The LocalFirst form without profile fields
|
|
665
|
+
remains the compatibility baseline.
|
|
666
|
+
|
|
667
|
+
The Rust API and CLI expose an optional `shared-postgresql` feature for
|
|
668
|
+
explicit shared deployments through
|
|
669
|
+
`PersistentKnowledgeRepositoryResolver::for_shared_postgresql` and workspace
|
|
670
|
+
request profile selection. Bare `PersistenceProfile::SharedPostgresql` still
|
|
671
|
+
fails closed before SQLite bootstrap because it has no secret-safe settings.
|
|
672
|
+
CLI request JSON rejects unknown fields so misspelled profile fields such as
|
|
673
|
+
`persistenceProfile` cannot be silently ignored and executed as LocalFirst.
|
|
674
|
+
|
|
675
|
+
Persistent-cache readiness and semantic vector readiness are separate gates.
|
|
676
|
+
`memory.cache.persist`, `memory.knowledge.query`, and `memory.context.package`
|
|
677
|
+
are reported independently so orchestrators can fail closed on the exact lane
|
|
678
|
+
they need.
|
|
679
|
+
Persistent cache payload hashes are built from canonical JSON so object order
|
|
680
|
+
and floating-point hydration differences do not invalidate durable cache rows
|
|
681
|
+
after they are read back from SQLite or PostgreSQL.
|
|
682
|
+
|
|
683
|
+
---
|
|
684
|
+
|
|
685
|
+
## Operations
|
|
686
|
+
|
|
687
|
+
Generated build output belongs under `.build/` and must not be committed.
|
|
688
|
+
|
|
689
|
+
Generated validation, packaging, publication, or release-candidate artifacts
|
|
690
|
+
belong under `.deployment/artifacts/` and must not be committed unless the
|
|
691
|
+
repository-specific release process explicitly publishes sanitized outputs.
|
|
692
|
+
|
|
693
|
+
The CI workflow runs automatically only for pushes to `main` and can also be
|
|
694
|
+
started with `workflow_dispatch`. It uses changed-file routing so docs-only
|
|
695
|
+
changes do not run Rust build or test stages.
|
|
696
|
+
|
|
697
|
+
---
|
|
698
|
+
|
|
699
|
+
## Planning
|
|
700
|
+
|
|
701
|
+
Use `planning/` for active plans, workstream status, release checklists, and
|
|
702
|
+
implementation checkpoints when the repository owns planning state.
|
|
703
|
+
|
|
704
|
+
Planning files must stay checklist-backed and evidence-backed. Close plans only
|
|
705
|
+
after the implementation, validation, review, and release or PR evidence are
|
|
706
|
+
recorded.
|
|
707
|
+
|
|
708
|
+
Completed enterprise RAG quality work is tracked in
|
|
709
|
+
`planning/completed/2026-05/202605210848-plan-memory-enterprise-rag-quality-pipeline.md`.
|
|
710
|
+
That plan covers Hybrid Search V2, reranking, contextual compression,
|
|
711
|
+
groundedness primitives, enterprise filters, CAG key scoping, and RAG quality
|
|
712
|
+
observability while keeping orchestration in `nettoolskit-copilot`. Hybrid
|
|
713
|
+
lexical ranking is BM25-style deterministic scoring and fusion; full
|
|
714
|
+
storage-backed search engines and conditional model decisions remain caller
|
|
715
|
+
architecture choices.
|
|
716
|
+
|
|
717
|
+
---
|
|
718
|
+
|
|
719
|
+
## Governance and Security
|
|
720
|
+
|
|
721
|
+
Use semantic branches such as `feat/...`, `fix/...`, `docs/...`,
|
|
722
|
+
`refactor/...`, `test/...`, `chore/...`, `ci/...`, and `release/...`.
|
|
723
|
+
|
|
724
|
+
Do not publish directly to `main` unless the repository owner explicitly asks
|
|
725
|
+
for that operation. Prefer PRs for all repository changes.
|
|
726
|
+
|
|
727
|
+
Do not commit secrets, tokens, usernames, database hostnames, connection
|
|
728
|
+
strings, machine-local paths, raw logs, local SQLite stores, vector indexes,
|
|
729
|
+
graph stores, `.env` files, or unsanitized release artifacts. Shared PostgreSQL
|
|
730
|
+
examples must reference environment variable names only. Release assets must be
|
|
731
|
+
reviewed for metadata leaks before publication.
|
|
732
|
+
|
|
733
|
+
---
|
|
734
|
+
|
|
735
|
+
## Build and Tests
|
|
736
|
+
|
|
737
|
+
Use targeted local validation for crate changes.
|
|
738
|
+
|
|
739
|
+
```powershell
|
|
740
|
+
cargo metadata --locked --format-version 1 --no-deps
|
|
741
|
+
cargo fmt --all --check
|
|
742
|
+
cargo clippy --locked --all-targets
|
|
743
|
+
cargo test --locked --no-fail-fast
|
|
744
|
+
cargo test --locked --features shared-postgresql --all-targets --no-fail-fast
|
|
745
|
+
git diff --check
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
---
|
|
749
|
+
|
|
750
|
+
## Contributing
|
|
751
|
+
|
|
752
|
+
Work from a semantic branch and keep changes scoped to this repository's
|
|
753
|
+
responsibility. Update `CHANGELOG.md` for user-visible, contract-level,
|
|
754
|
+
release, CI/CD, governance, or dependency changes.
|
|
755
|
+
|
|
756
|
+
Keep generated outputs under `.build/` and local artifacts under
|
|
757
|
+
`.deployment/artifacts/`.
|
|
758
|
+
|
|
759
|
+
---
|
|
760
|
+
|
|
761
|
+
## Dependencies
|
|
762
|
+
|
|
763
|
+
- Runtime: none in the foundation PR.
|
|
764
|
+
- Development: GitHub template baseline.
|
|
765
|
+
|
|
766
|
+
---
|
|
767
|
+
|
|
768
|
+
## References
|
|
769
|
+
|
|
770
|
+
- [Changelog](CHANGELOG.md)
|
|
771
|
+
- [Planning](planning/README.md)
|
|
772
|
+
- [GitHub Repository](https://github.com/NetToolsKit/nettoolskit-memory)
|
|
773
|
+
|
|
774
|
+
---
|
|
775
|
+
|
|
776
|
+
## License
|
|
777
|
+
|
|
778
|
+
This project is licensed under the MIT License. See the LICENSE file at the
|
|
779
|
+
repository root for details.
|
|
780
|
+
|
|
781
|
+
## npm and npx
|
|
782
|
+
|
|
783
|
+
This repository exposes the `ntk-memory` command through the `@nettoolskit/memory` npm package for local installation and `npx` execution.
|
|
784
|
+
|
|
785
|
+
```powershell
|
|
786
|
+
npm install -g @nettoolskit/memory
|
|
787
|
+
ntk-memory --help
|
|
788
|
+
npx @nettoolskit/memory --help
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
The npm wrapper executes a native `ntk-memory` binary from `npm/native/` when release packaging stages one. For development or private release validation, set `NTK_MEMORY_BINARY` to an already built local binary. Use `npm run stage:native -- <path-to-binary>` before packaging a native tarball.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const { spawnSync } = require("node:child_process");
|
|
5
|
+
const fs = require("node:fs");
|
|
6
|
+
const path = require("node:path");
|
|
7
|
+
|
|
8
|
+
const repoRoot = path.resolve(__dirname, "..", "..");
|
|
9
|
+
const nativeName = process.platform === "win32" ? "ntk-memory.exe" : "ntk-memory";
|
|
10
|
+
const bundledBinary = path.join(repoRoot, "npm", "native", nativeName);
|
|
11
|
+
const explicitBinary = process.env.NTK_MEMORY_BINARY || process.env.NETTOOLSKIT_MEMORY_BINARY;
|
|
12
|
+
|
|
13
|
+
function executableExists(candidate) {
|
|
14
|
+
return Boolean(candidate) && fs.existsSync(candidate);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function spawnPath(candidate) {
|
|
18
|
+
return process.platform === "win32" ? path.toNamespacedPath(candidate) : candidate;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function failMissingBinary(detail) {
|
|
22
|
+
console.error("ntk-memory binary was not found.");
|
|
23
|
+
if (detail) {
|
|
24
|
+
console.error(detail);
|
|
25
|
+
}
|
|
26
|
+
console.error("Set NTK_MEMORY_BINARY to a local binary or install a package built with npm/native/ntk-memory.");
|
|
27
|
+
process.exit(127);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let binary;
|
|
31
|
+
if (explicitBinary) {
|
|
32
|
+
if (!executableExists(explicitBinary)) {
|
|
33
|
+
failMissingBinary("Configured ntk-memory binary does not exist: " + explicitBinary);
|
|
34
|
+
}
|
|
35
|
+
binary = explicitBinary;
|
|
36
|
+
} else if (executableExists(bundledBinary)) {
|
|
37
|
+
binary = bundledBinary;
|
|
38
|
+
} else {
|
|
39
|
+
failMissingBinary("Expected bundled binary at: " + bundledBinary);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const result = spawnSync(spawnPath(binary), process.argv.slice(2), {
|
|
43
|
+
stdio: "inherit",
|
|
44
|
+
windowsHide: true,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
if (result.error) {
|
|
48
|
+
failMissingBinary(result.error.message);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (typeof result.status === "number") {
|
|
52
|
+
process.exit(result.status);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
process.exit(1);
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@nettoolskit/memory",
|
|
3
|
+
"version": "0.0.1-preview.1",
|
|
4
|
+
"description": "Knowledge ingestion, local memory, RAG, HyDE, retrieval, context packages, and vault materialization for NetToolsKit.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"nettoolskit",
|
|
8
|
+
"memory",
|
|
9
|
+
"cli",
|
|
10
|
+
"npx"
|
|
11
|
+
],
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/NetToolsKit/nettoolskit-memory.git"
|
|
15
|
+
},
|
|
16
|
+
"homepage": "https://github.com/NetToolsKit/nettoolskit-memory#readme",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/NetToolsKit/nettoolskit-memory/issues"
|
|
19
|
+
},
|
|
20
|
+
"bin": {
|
|
21
|
+
"ntk-memory": "npm/cli/ntk-memory.js"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"LICENSE",
|
|
25
|
+
"README.md",
|
|
26
|
+
"npm/cli/ntk-memory.js",
|
|
27
|
+
"npm/native/",
|
|
28
|
+
"scripts/npm/postinstall.js",
|
|
29
|
+
"scripts/npm/stage-native.js"
|
|
30
|
+
],
|
|
31
|
+
"scripts": {
|
|
32
|
+
"postinstall": "node scripts/npm/postinstall.js",
|
|
33
|
+
"stage:native": "node scripts/npm/stage-native.js",
|
|
34
|
+
"pack:dry-run": "npm pack --ignore-scripts --dry-run"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=18"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
|
|
7
|
+
const nativeName = process.platform === "win32" ? "ntk-memory.exe" : "ntk-memory";
|
|
8
|
+
const nativePath = path.resolve(__dirname, "..", "..", "npm", "native", nativeName);
|
|
9
|
+
|
|
10
|
+
if (process.env.NTK_MEMORY_SKIP_POSTINSTALL === "1") {
|
|
11
|
+
process.exit(0);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (fs.existsSync(nativePath)) {
|
|
15
|
+
process.exit(0);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
console.warn("ntk-memory native binary is not bundled in this installation.");
|
|
19
|
+
console.warn("Use NTK_MEMORY_BINARY to point to a local binary or run npm run stage:native before publishing a native package.");
|
|
20
|
+
process.exit(0);
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
const fs = require("node:fs");
|
|
5
|
+
const path = require("node:path");
|
|
6
|
+
|
|
7
|
+
const binaryName = process.platform === "win32" ? "ntk-memory.exe" : "ntk-memory";
|
|
8
|
+
const repoRoot = path.resolve(__dirname, "..", "..");
|
|
9
|
+
const explicitSource = process.argv[2] || process.env.NTK_MEMORY_STAGE_BINARY;
|
|
10
|
+
const candidates = [
|
|
11
|
+
explicitSource,
|
|
12
|
+
path.join(repoRoot, "target", "release", binaryName),
|
|
13
|
+
path.join(repoRoot, "target", "x86_64-pc-windows-msvc", "release", "ntk-memory.exe"),
|
|
14
|
+
path.join(repoRoot, "target", "x86_64-unknown-linux-gnu", "release", "ntk-memory"),
|
|
15
|
+
].filter(Boolean);
|
|
16
|
+
|
|
17
|
+
const source = candidates.find((candidate) => fs.existsSync(candidate));
|
|
18
|
+
if (!source) {
|
|
19
|
+
console.error("No ntk-memory release binary found to stage.");
|
|
20
|
+
console.error("Build the release binary first or set NTK_MEMORY_STAGE_BINARY.");
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const nativeDir = path.join(repoRoot, "npm", "native");
|
|
25
|
+
fs.mkdirSync(nativeDir, { recursive: true });
|
|
26
|
+
const destination = path.join(nativeDir, binaryName);
|
|
27
|
+
fs.copyFileSync(source, destination);
|
|
28
|
+
if (process.platform !== "win32") {
|
|
29
|
+
fs.chmodSync(destination, 0o755);
|
|
30
|
+
}
|
|
31
|
+
console.log("Staged " + source + " -> " + destination);
|