@memory-river/core 0.2.0
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 +201 -0
- package/README.md +222 -0
- package/README.zh-TW.md +186 -0
- package/dist/api.d.ts +100 -0
- package/dist/api.js +156 -0
- package/dist/cognition/causal-attribution.d.ts +36 -0
- package/dist/cognition/causal-attribution.js +239 -0
- package/dist/cognition/causal-engine.d.ts +105 -0
- package/dist/cognition/causal-engine.js +150 -0
- package/dist/cognition/conflict-detector.d.ts +39 -0
- package/dist/cognition/conflict-detector.js +193 -0
- package/dist/cognition/global-working-memory.d.ts +53 -0
- package/dist/cognition/global-working-memory.js +211 -0
- package/dist/cognition/hooks-engine.d.ts +99 -0
- package/dist/cognition/hooks-engine.js +672 -0
- package/dist/cognition/ralph-core.d.ts +28 -0
- package/dist/cognition/ralph-core.js +104 -0
- package/dist/distill/concentrator-adapter.d.ts +167 -0
- package/dist/distill/concentrator-adapter.js +1876 -0
- package/dist/engine.d.ts +402 -0
- package/dist/engine.js +2254 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +3 -0
- package/dist/lifecycle/cleanup-engine.d.ts +80 -0
- package/dist/lifecycle/cleanup-engine.js +162 -0
- package/dist/lifecycle/cleanup-state.d.ts +34 -0
- package/dist/lifecycle/cleanup-state.js +50 -0
- package/dist/lifecycle/night-consolidation.d.ts +102 -0
- package/dist/lifecycle/night-consolidation.js +640 -0
- package/dist/lifecycle/night-recovery.d.ts +40 -0
- package/dist/lifecycle/night-recovery.js +107 -0
- package/dist/paths.d.ts +17 -0
- package/dist/paths.js +16 -0
- package/dist/pipeline/capsule-bridge.d.ts +35 -0
- package/dist/pipeline/capsule-bridge.js +86 -0
- package/dist/pipeline/compact-request.d.ts +30 -0
- package/dist/pipeline/compact-request.js +66 -0
- package/dist/pipeline/inbox-watcher.d.ts +112 -0
- package/dist/pipeline/inbox-watcher.js +1039 -0
- package/dist/ports.d.ts +29 -0
- package/dist/ports.js +1 -0
- package/dist/providers/embedder-v5.d.ts +46 -0
- package/dist/providers/embedder-v5.js +155 -0
- package/dist/providers/ollama-embedding.d.ts +25 -0
- package/dist/providers/ollama-embedding.js +166 -0
- package/dist/retrieval/abstractness-judge.d.ts +14 -0
- package/dist/retrieval/abstractness-judge.js +87 -0
- package/dist/retrieval/coverage-selection.d.ts +3 -0
- package/dist/retrieval/coverage-selection.js +53 -0
- package/dist/retrieval/cross-encoder-gate.d.ts +40 -0
- package/dist/retrieval/cross-encoder-gate.js +239 -0
- package/dist/retrieval/retriever-v4.d.ts +78 -0
- package/dist/retrieval/retriever-v4.js +1200 -0
- package/dist/skills/validate.d.ts +6 -0
- package/dist/skills/validate.js +69 -0
- package/dist/storage.d.ts +19 -0
- package/dist/storage.js +54 -0
- package/dist/store/aux-table-maintenance.d.ts +5 -0
- package/dist/store/aux-table-maintenance.js +64 -0
- package/dist/store/graph-enumerator.d.ts +21 -0
- package/dist/store/graph-enumerator.js +185 -0
- package/dist/store/graph-store.d.ts +107 -0
- package/dist/store/graph-store.js +478 -0
- package/dist/store/status-manager.d.ts +44 -0
- package/dist/store/status-manager.js +235 -0
- package/dist/store/store-v4.d.ts +339 -0
- package/dist/store/store-v4.js +2871 -0
- package/dist/transcript/keyword-search.d.ts +9 -0
- package/dist/transcript/keyword-search.js +67 -0
- package/dist/transcript/rehydrate-keyword.d.ts +6 -0
- package/dist/transcript/rehydrate-keyword.js +29 -0
- package/dist/transcript/rehydrate.d.ts +33 -0
- package/dist/transcript/rehydrate.js +285 -0
- package/dist/transcript/transcript-archive.d.ts +46 -0
- package/dist/transcript/transcript-archive.js +516 -0
- package/dist/types.d.ts +409 -0
- package/dist/types.js +104 -0
- package/dist/util/bounded-map.d.ts +1 -0
- package/dist/util/bounded-map.js +8 -0
- package/dist/util/rate-limiter.d.ts +12 -0
- package/dist/util/rate-limiter.js +54 -0
- package/dist/util/session-identity.d.ts +65 -0
- package/dist/util/session-identity.js +227 -0
- package/dist/util/util-hash.d.ts +1 -0
- package/dist/util/util-hash.js +4 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright 2026 Hsi431
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# @memory-river/core
|
|
2
|
+
|
|
3
|
+
**Three-tier memory for agents — a working recap that fades, durable facts that persist, and the full transcript it can always go back and re-read.**
|
|
4
|
+
|
|
5
|
+
[繁體中文](./README.zh-TW.md)
|
|
6
|
+
|
|
7
|
+
Most "agent memory" is a vector store with a save button: one flat pile of embeddings you write to and search. Memory River is a memory *system* modeled on how memory actually works — it keeps information at **three timescales**, retrieves it in **two passes**, lets memories **metabolize** over time, and can trace anything it distilled back to the exact turns it came from. You inject your own embedding and LLM providers; the engine is host-independent.
|
|
8
|
+
|
|
9
|
+
> `0.2.x` is an early API. Review upgrades before adopting a new minor release.
|
|
10
|
+
|
|
11
|
+
## The idea: three timescales of memory
|
|
12
|
+
|
|
13
|
+
When a conversation grows past a watermark, Memory River doesn't just truncate the old turns — it **distills** them into memory at three timescales:
|
|
14
|
+
|
|
15
|
+
- **Short term — the session capsule.** A compact recap of what just happened, injected at the top of the next prompt so the model keeps the thread after old turns are cut. It starts at low health and **metabolizes fast** — this is working memory for *this* session, not a fact store. The capsule is domain-adaptive: a coding session gets a structured task summary; a casual conversation gets a natural-language recap.
|
|
16
|
+
- **Medium term — distilled notes.** Alongside each capsule, a handful of granular, self-contained facts are extracted and written to the store as ordinary memories. They start at full health and **persist** — this is what `recall` surfaces days later.
|
|
17
|
+
- **Long term — the raw transcript.** Every turn is archived verbatim with a byte-offset index, and the session capsule records the exact turns it summarized — so nothing is ever truly lost to compression.
|
|
18
|
+
|
|
19
|
+
## Retrieval in two passes
|
|
20
|
+
|
|
21
|
+
1. **Coarse recall (automatic, cheap).** Before a model turn, `assembleContext` injects the top couple of relevant memories. Always on.
|
|
22
|
+
2. **Rehydrate (precise, on demand).** A lossy memory carries pointers back to its source turns; the agent calls `rehydrate` to pull the **exact original turns** — verbatim numbers, names, dates — by entry-id, time window, or keyword.
|
|
23
|
+
|
|
24
|
+
The common case stays cheap (you don't reload the whole conversation every turn), but precise detail is never more than one hop away. This is also what makes Memory River **auditable**: every distilled claim can be traced to the source turns that produced it.
|
|
25
|
+
|
|
26
|
+
## Memory that metabolizes
|
|
27
|
+
|
|
28
|
+
Memories aren't write-once rows. They **live**: health decays over time and refreshes on access; a newer fact **supersedes** a close older one; contradictions are **flagged and deprecated** instead of silently coexisting; a nightly pass **merges** redundant memories; dead memories are cleaned up through a trash-protected path. Core categories, high-importance facts, and skill capsules are protected from decay — so the store stays relevant instead of growing into noise.
|
|
29
|
+
|
|
30
|
+
## How it's built
|
|
31
|
+
|
|
32
|
+
| Subsystem | What it does | Module |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| Dual-tier store + WAL | RAM-dir (e.g. tmpfs) for hot reads, data-dir for durability, write-ahead log with crash recovery | `store/store-v4` |
|
|
35
|
+
| Distillation pipeline | Old turns are summarized into a capsule + granular notes, written through an async inbox so writes never block the conversation | `distill/concentrator-adapter` + `pipeline/inbox-watcher` |
|
|
36
|
+
| Transcript + rehydrate | Verbatim turn archive with a byte-offset `.idx`; recover exact turns by entry-id, time, or keyword | `transcript/` |
|
|
37
|
+
| Hybrid retrieval | Vector + full-text BM25, RRF fusion, optional local rerank (CRAG-style accept/partial/reject, tuned recall-safe), EntitySynergyMerger (NER fragment rescue), Structured-Slot dedup, causal-chain context expansion | `retrieval/retriever-v4` |
|
|
38
|
+
| Knowledge graph | Triple (subject–relation–object) store with vector + FTS entity search, used to expand hook/query coverage | `store/graph-store` |
|
|
39
|
+
| Memory metabolism | Health decays over time, refreshes on access; dead memories cleaned up through a trash-protected path | `lifecycle/cleanup-engine` |
|
|
40
|
+
| Night consolidation | Periodic offline pass that merges and compresses related memories | `lifecycle/night-consolidation` |
|
|
41
|
+
| Associative hooks | Memories can carry trigger keywords that fire related recalls; a feedback loop reweights hooks by hit quality | `cognition/hooks-engine` |
|
|
42
|
+
| Causal + conflict | Newer facts supersede close older ones; contradictions are flagged and deprecated with a `supersededBy` chain | `cognition/causal-engine` + `conflict-detector` |
|
|
43
|
+
| Structured slots | Extracts structured params (slotKey/slotValue) at write time with a version chain; retrieval returns only the latest active per slot | `pipeline/inbox-watcher` + `retrieval/retriever-v4` |
|
|
44
|
+
| Global Working Memory (GWM) | Tracks the long-conversation task; embedding drift detection nudges the agent back on topic | `cognition/global-working-memory` |
|
|
45
|
+
| Skill capsules v2 | Explicitly saved procedures with progressive disclosure: a one-line index is injected, full steps load on demand | `engine` + `skills/` |
|
|
46
|
+
| Ralph Loop | Context circuit-breaker: on repeated failures it trims/truncates context and injects warnings to keep context from blowing up | `cognition/ralph-core` |
|
|
47
|
+
| Observability | Every subsystem writes best-effort stats rows (`subsystem_effectiveness`, `status_audit_log`, …) you can audit later | throughout |
|
|
48
|
+
|
|
49
|
+
Everything above is in the code today — this README intentionally describes nothing aspirational.
|
|
50
|
+
|
|
51
|
+
## Requirements
|
|
52
|
+
|
|
53
|
+
- Node.js 20
|
|
54
|
+
- An `EmbeddingProvider` (a ready-made `OllamaEmbedding` is included)
|
|
55
|
+
- An `LlmClient` (any function that turns a prompt into text — see Quick Start)
|
|
56
|
+
- Two writable directories (`dataDir` for durability, `ramDir` for the hot tier — tmpfs if you have it, any disk dir works)
|
|
57
|
+
|
|
58
|
+
Optional native deps degrade gracefully: `nodejieba` (CJK tokenization, falls back to character split) and `@xenova/transformers` (local reranker, falls back to pass-through).
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm install @memory-river/core
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
In this monorepo:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm ci
|
|
70
|
+
npm run build -w @memory-river/core
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Quick Start
|
|
74
|
+
|
|
75
|
+
The repository's [`example-cli`](../example-cli/src/cli.ts) (~110 lines) is a complete non-OpenClaw integration using Ollama for both embeddings and chat:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
ollama pull hf.co/Qwen/Qwen3-Embedding-0.6B-GGUF
|
|
79
|
+
ollama pull qwen3:8b
|
|
80
|
+
npm run build -ws
|
|
81
|
+
|
|
82
|
+
node packages/example-cli/dist/cli.js remember "The deployment window is Friday at 18:00."
|
|
83
|
+
node packages/example-cli/dist/cli.js recall "When is deployment?"
|
|
84
|
+
node packages/example-cli/dist/cli.js chat
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The equivalent core setup:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import {
|
|
91
|
+
createMemoryRiver,
|
|
92
|
+
OllamaEmbedding,
|
|
93
|
+
type LlmClient,
|
|
94
|
+
} from '@memory-river/core';
|
|
95
|
+
|
|
96
|
+
const ollamaUrl = 'http://localhost:11434';
|
|
97
|
+
|
|
98
|
+
const llm: LlmClient = {
|
|
99
|
+
async generate(prompt, opts) {
|
|
100
|
+
const response = await fetch(`${ollamaUrl}/v1/chat/completions`, {
|
|
101
|
+
method: 'POST',
|
|
102
|
+
headers: { 'content-type': 'application/json' },
|
|
103
|
+
body: JSON.stringify({
|
|
104
|
+
model: 'qwen3:8b',
|
|
105
|
+
messages: [{ role: 'user', content: prompt }],
|
|
106
|
+
max_tokens: opts?.maxTokens,
|
|
107
|
+
}),
|
|
108
|
+
});
|
|
109
|
+
if (!response.ok) throw new Error(`LLM request failed: ${response.status}`);
|
|
110
|
+
const body = await response.json() as any;
|
|
111
|
+
return body.choices?.[0]?.message?.content ?? '';
|
|
112
|
+
},
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const embedder = new OllamaEmbedding({
|
|
116
|
+
provider: 'ollama',
|
|
117
|
+
apiKey: '',
|
|
118
|
+
model: 'hf.co/Qwen/Qwen3-Embedding-0.6B-GGUF',
|
|
119
|
+
dimensions: 1024,
|
|
120
|
+
ollamaUrl,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const river = createMemoryRiver(
|
|
124
|
+
{
|
|
125
|
+
dataDir: '/var/lib/my-agent/memory-river',
|
|
126
|
+
ramDir: '/var/lib/my-agent/memory-river/ram',
|
|
127
|
+
autoRecall: true,
|
|
128
|
+
},
|
|
129
|
+
{ embedder, llm },
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
await river.start();
|
|
133
|
+
try {
|
|
134
|
+
await river.remember('The deployment window is Friday at 18:00.', {
|
|
135
|
+
category: 'fact',
|
|
136
|
+
importance: 0.8,
|
|
137
|
+
});
|
|
138
|
+
const results = await river.recall('When is deployment?', 5);
|
|
139
|
+
console.log(results);
|
|
140
|
+
} finally {
|
|
141
|
+
await river.stop();
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
`start()` initializes the engine, starts the inbox watcher, and schedules maintenance. `stop()` stops watchers and timers and shuts down the memory store.
|
|
146
|
+
|
|
147
|
+
## API
|
|
148
|
+
|
|
149
|
+
`createMemoryRiver(config, deps)` returns:
|
|
150
|
+
|
|
151
|
+
| API | Purpose |
|
|
152
|
+
| --- | --- |
|
|
153
|
+
| `start()` / `stop()` | Engine lifecycle. |
|
|
154
|
+
| `remember(text, opts?)` | Store a memory with optional category, importance, metadata. |
|
|
155
|
+
| `recall(query, limit?)` | Ranked `MemorySearchResult` records from hybrid retrieval. |
|
|
156
|
+
| `assembleContext(messages, session?)` | Inject relevant memories (and the skill index) into a message list before a model turn. |
|
|
157
|
+
| `skills.save / load / search / list` | Skill capsules v2 — see below. |
|
|
158
|
+
| `rehydrate(request)` | Read archived transcript entries by IDs, time range, or keyword. |
|
|
159
|
+
| `archiveTranscript(session, messages)` | Append host messages to the transcript archive. |
|
|
160
|
+
| `compactSessionFile(session, opts?)` | Compact a host session file when `SessionFileAccess` resolves one. |
|
|
161
|
+
| `gwm.on/off/status/update` | Global Working Memory state (goal tracking + drift detection). |
|
|
162
|
+
| `maintenance.runCleanup()` / `runNightConsolidation()` | Trigger maintenance manually. |
|
|
163
|
+
|
|
164
|
+
`MemoryRiverConfig` requires `dataDir` and `ramDir`; everything else (`embedding`, `retrieval`, `cleanup`, `health`, `hooks`, `causalEngine`, `concentration`, `autoRecall`, `driftThreshold`, …) is optional and merged with defaults.
|
|
165
|
+
|
|
166
|
+
## Skill Capsules v2
|
|
167
|
+
|
|
168
|
+
Skills are procedures your agent explicitly saves — the system never auto-generates them:
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
await river.skills.save({
|
|
172
|
+
name: 'git-release',
|
|
173
|
+
summary: 'Tag and push a release the standard way',
|
|
174
|
+
triggers: ['release', 'tag a version'],
|
|
175
|
+
steps: ['Run the test suite', 'git tag -s vX.Y.Z', 'git push --tags', 'Draft release notes'],
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
- **Progressive disclosure**: `assembleContext` injects only a one-line index (`【git-release】triggers… → skill_load("git-release")`); full steps cost zero tokens until the agent calls `skills.load`.
|
|
180
|
+
- **Honest usage stats**: only `load` increments `usageCount` — being injected doesn't count as being used.
|
|
181
|
+
- **Lifecycle**: skills decay 4× slower than ordinary memories and heal on every load; unused ones eventually fade out instead of polluting the index forever.
|
|
182
|
+
- **Deterministic quality gate**: malformed definitions are rejected with every violation listed at once — no LLM judging, no silent fixes.
|
|
183
|
+
|
|
184
|
+
## Dependency Ports
|
|
185
|
+
|
|
186
|
+
The host owns external services. Required: `embedder`, `llm`. Optional: `logger`, `notifier`, `sessionFiles`.
|
|
187
|
+
|
|
188
|
+
```ts
|
|
189
|
+
interface EmbeddingProvider {
|
|
190
|
+
embed(text: string, mode?: 'store' | 'query'): Promise<number[]>;
|
|
191
|
+
embedBatch(texts: string[]): Promise<number[][]>;
|
|
192
|
+
getDimensions(): number;
|
|
193
|
+
healthCheck?(): Promise<boolean>;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
interface LlmClient {
|
|
197
|
+
generate(prompt: string, opts?: { purpose?: string; maxTokens?: number }): Promise<string>;
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
Provider selection, retries, fallback, and rate limiting belong in your `LlmClient` — core deliberately does not ship a multi-provider fallback chain.
|
|
202
|
+
|
|
203
|
+
`Logger` defaults to console. `Notifier` defaults to no-op. Without `SessionFileAccess`, transcript archiving and rehydration still work; only `compactSessionFile()` becomes a no-op.
|
|
204
|
+
|
|
205
|
+
## Porting to Another Agent Host
|
|
206
|
+
|
|
207
|
+
1. Pick writable `dataDir` + `ramDir`.
|
|
208
|
+
2. Implement `EmbeddingProvider` (or use `OllamaEmbedding`).
|
|
209
|
+
3. Implement `LlmClient` (~20 lines for any OpenAI-compatible endpoint).
|
|
210
|
+
4. `createMemoryRiver(...)`, `start()` on host startup, `stop()` on shutdown.
|
|
211
|
+
5. Expose `remember` / `recall` (and optionally `skills.save` / `skills.load`) as host tools.
|
|
212
|
+
|
|
213
|
+
That's a working integration — `example-cli` is exactly this and fits in ~110 lines. Steps 6–9 are optional layers: pass conversations through `assembleContext`, archive transcripts for `rehydrate`, wire `SessionFileAccess` for session-file compaction, connect `Logger`/`Notifier`.
|
|
214
|
+
|
|
215
|
+
## Persistence Notes
|
|
216
|
+
|
|
217
|
+
LanceDB-backed dual-tier storage plus a WAL. Inserts are WAL-protected before the call returns; replay is idempotent and a failed replay preserves the log for the next attempt. The package does not claim exactly-once recovery or zero data loss — treat the data directory as application state and back it up accordingly.
|
|
218
|
+
|
|
219
|
+
## License
|
|
220
|
+
|
|
221
|
+
Apache-2.0 © 2026 Hsi431. Use, modify, embed, and ship freely under the permissive
|
|
222
|
+
Apache 2.0 terms. See the repository-root [LICENSE](../../LICENSE).
|
package/README.zh-TW.md
ADDED
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# @memory-river/core
|
|
2
|
+
|
|
3
|
+
**給 agent 的三層記憶 — 會褪色的工作摘要、會留存的事實、以及永遠能回頭重讀的完整原文。**
|
|
4
|
+
|
|
5
|
+
[English](./README.md)
|
|
6
|
+
|
|
7
|
+
大多數「agent 記憶」就是一個 vector store 加一顆儲存鍵:一坨平的 embedding,你往裡寫、往裡搜。Memory River 是一套**模擬真實記憶運作**的記憶*系統* — 它把資訊保存在**三種時間尺度**、用**兩段式**檢索、讓記憶隨時間**代謝**,而且任何被蒸餾出來的東西都能**追溯回它來自哪幾句原文**。embedding 和 LLM 由你注入,引擎本身不綁任何宿主框架。
|
|
8
|
+
|
|
9
|
+
> `0.2.x` 是早期 API,升版前請先看變更。
|
|
10
|
+
|
|
11
|
+
## 核心概念:三種時間尺度的記憶
|
|
12
|
+
|
|
13
|
+
當對話長過水位線,Memory River 不是把舊對話截掉就算了 — 它把舊對話**蒸餾**成三種時間尺度的記憶:
|
|
14
|
+
|
|
15
|
+
- **短期 — session 膠囊。** 剛剛發生了什麼的精簡前情提要,注入下一個 prompt 頂端,讓模型在舊對話被裁切後仍接得上脈絡。它起始健康度低、**代謝得快** — 這是*這次 session* 的工作記憶,不是事實庫。膠囊會依領域自適應:寫程式的 session 給結構化任務摘要,閒聊給自然語言前情提要。
|
|
16
|
+
- **中期 — 蒸餾筆記。** 每顆膠囊旁邊,會抽出幾條顆粒化、可獨立理解的事實,當作一般記憶寫進庫裡。它們起始滿血、**會留存** — 幾天後 `recall` 撈到的就是這些。
|
|
17
|
+
- **長期 — 原始 transcript。** 每一句對話都逐字歸檔,帶 byte-offset 索引;膠囊會記下它摘要了哪幾句確切原文 — 所以壓縮不會真的丟失任何東西。
|
|
18
|
+
|
|
19
|
+
## 兩段式檢索
|
|
20
|
+
|
|
21
|
+
1. **粗召回(自動、便宜)。** 模型回合前,`assembleContext` 注入最相關的少數幾條記憶。永遠開著。
|
|
22
|
+
2. **Rehydrate(精確、按需)。** 失真的記憶會帶著回指原文的指標;agent 呼叫 `rehydrate`,用 entry-id、時間窗或關鍵字撈回**確切的原始對話** — 逐字的數字、人名、日期。
|
|
23
|
+
|
|
24
|
+
常態很便宜(你不必每回合重載整段對話),但精確細節永遠只差一跳。這也讓 Memory River **可稽核**:每一條蒸餾出的結論,都能追回產生它的那幾句原文。
|
|
25
|
+
|
|
26
|
+
## 會代謝的記憶
|
|
27
|
+
|
|
28
|
+
記憶不是寫一次就不動的列。它們**會活**:健康度隨時間衰減、被存取就回血;新事實會**取代**相近的舊事實;矛盾會被**標記並 deprecated**,而不是默默並存;夜間有一趟把冗餘記憶**合併**;歸零的記憶走 trash 保護路徑清掉。核心類別、高重要性事實、技能膠囊免於衰減 — 所以記憶庫保持相關,而不是長成一堆雜訊。
|
|
29
|
+
|
|
30
|
+
## 怎麼蓋起來的
|
|
31
|
+
|
|
32
|
+
| 子系統 | 做什麼 | 模組 |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| 雙層儲存 + WAL | RAM 目錄(可放 tmpfs)做熱讀、資料目錄做持久層、write-ahead log 含當機恢復 | `store/store-v4` |
|
|
35
|
+
| 蒸餾管線 | 舊對話被摘成膠囊 + 顆粒化筆記,經非同步 inbox 寫入 — 寫入永不阻塞對話 | `distill/concentrator-adapter` + `pipeline/inbox-watcher` |
|
|
36
|
+
| Transcript + rehydrate | 逐字原文歸檔 + byte-offset `.idx`;用 entry-id、時間、關鍵字撈回確切原文 | `transcript/` |
|
|
37
|
+
| Hybrid 檢索 | 向量 + 全文 BM25、RRF 融合、可選的本地 cross-encoder rerank(CRAG 式 accept/partial/reject,調在 recall 安全端)、EntitySynergyMerger(NER 碎片搶救)、Structured Slot 去重、因果鏈上下文擴展 | `retrieval/retriever-v4` |
|
|
38
|
+
| 知識圖譜 | 三元組(subject–relation–object)儲存,向量 + FTS 實體搜尋,供鉤子做語意查詢擴展 | `store/graph-store` |
|
|
39
|
+
| 記憶代謝 | 健康度隨時間衰減、被存取就回血;歸零的記憶走 trash 保護路徑清掉 | `lifecycle/cleanup-engine` |
|
|
40
|
+
| 夜間整理 | 週期性離線合併、壓縮相關記憶 | `lifecycle/night-consolidation` |
|
|
41
|
+
| 聯想鉤子 | 記憶可帶觸發關鍵字,命中時連帶喚起相關記憶;命中成效有回饋閉環動態調權 | `cognition/hooks-engine` |
|
|
42
|
+
| 因果 + 衝突 | 新事實取代相近舊事實;矛盾被標記並 deprecated 並記 `supersededBy` 追溯鏈 | `cognition/causal-engine` + `conflict-detector` |
|
|
43
|
+
| Structured Slot | 寫入時抽結構化參數(slotKey/slotValue)+ 版本鏈;檢索時同 slot 只回最新 active | `pipeline/inbox-watcher` + `retrieval/retriever-v4` |
|
|
44
|
+
| 全局工作記憶 (GWM) | 追蹤長對話主任務,embedding 漂移偵測,偏題時注入提醒拉回 | `cognition/global-working-memory` |
|
|
45
|
+
| 技能膠囊 v2 | 顯式儲存的程序性知識,漸進式揭露:平時只注入一行索引,要用才載入完整步驟 | `engine` + `skills/` |
|
|
46
|
+
| Ralph Loop | context 斷路器:連續失敗時修剪 / 截斷 context、注入警告,防 context 爆掉 | `cognition/ralph-core` |
|
|
47
|
+
| 可觀測性 | 每個子系統 best-effort 寫統計列(`subsystem_effectiveness`、`status_audit_log`…),事後可稽核 | 遍布全系統 |
|
|
48
|
+
|
|
49
|
+
以上每一項都是現在 code 裡真的有的 — 這份 README 刻意不描述任何「願景」。
|
|
50
|
+
|
|
51
|
+
## 需求
|
|
52
|
+
|
|
53
|
+
- Node.js 20
|
|
54
|
+
- 一個 `EmbeddingProvider`(內建 `OllamaEmbedding` 可直接用)
|
|
55
|
+
- 一個 `LlmClient`(任何「prompt 進、文字出」的函式 — 見 Quick Start)
|
|
56
|
+
- 兩個可寫目錄(`dataDir` 持久層、`ramDir` 熱層 — 有 tmpfs 用 tmpfs,一般磁碟目錄也行)
|
|
57
|
+
|
|
58
|
+
可選的原生依賴都能優雅降級:`nodejieba`(中日韓斷詞,缺了退回逐字切)、`@xenova/transformers`(本地 reranker,缺了直通)。
|
|
59
|
+
|
|
60
|
+
## 安裝
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm install @memory-river/core
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
在這個 monorepo 裡:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm ci
|
|
70
|
+
npm run build -w @memory-river/core
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Quick Start
|
|
74
|
+
|
|
75
|
+
repo 裡的 [`example-cli`](../example-cli/src/cli.ts)(約 110 行)就是一個完整的非 OpenClaw 整合,embedding 和聊天都走 Ollama:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
ollama pull hf.co/Qwen/Qwen3-Embedding-0.6B-GGUF
|
|
79
|
+
ollama pull qwen3:8b
|
|
80
|
+
npm run build -ws
|
|
81
|
+
|
|
82
|
+
node packages/example-cli/dist/cli.js remember "老闆喜歡手沖咖啡"
|
|
83
|
+
node packages/example-cli/dist/cli.js recall "咖啡"
|
|
84
|
+
node packages/example-cli/dist/cli.js chat
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
等價的 core 寫法(完整版見英文 README,只差字串語言):
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import { createMemoryRiver, OllamaEmbedding } from '@memory-river/core';
|
|
91
|
+
|
|
92
|
+
const river = createMemoryRiver(
|
|
93
|
+
{
|
|
94
|
+
dataDir: '/var/lib/my-agent/memory-river',
|
|
95
|
+
ramDir: '/var/lib/my-agent/memory-river/ram',
|
|
96
|
+
autoRecall: true,
|
|
97
|
+
},
|
|
98
|
+
{ embedder, llm }, // 你注入的 EmbeddingProvider 與 LlmClient
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
await river.start();
|
|
102
|
+
try {
|
|
103
|
+
await river.remember('老闆喜歡手沖咖啡', { category: 'preference', importance: 0.8 });
|
|
104
|
+
console.log(await river.recall('咖啡', 5));
|
|
105
|
+
} finally {
|
|
106
|
+
await river.stop();
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`start()` 初始化引擎、啟動 inbox watcher、排程維護;`stop()` 停掉 watcher 與 timer 並關閉儲存層。
|
|
111
|
+
|
|
112
|
+
## API
|
|
113
|
+
|
|
114
|
+
`createMemoryRiver(config, deps)` 回傳:
|
|
115
|
+
|
|
116
|
+
| API | 用途 |
|
|
117
|
+
| --- | --- |
|
|
118
|
+
| `start()` / `stop()` | 引擎生命週期。 |
|
|
119
|
+
| `remember(text, opts?)` | 存記憶,可帶 category、importance、metadata。 |
|
|
120
|
+
| `recall(query, limit?)` | hybrid 檢索的排序結果。 |
|
|
121
|
+
| `assembleContext(messages, session?)` | 模型回合前,把相關記憶(與技能索引)注入訊息列。 |
|
|
122
|
+
| `skills.save / load / search / list` | 技能膠囊 v2,見下節。 |
|
|
123
|
+
| `rehydrate(request)` | 按 ID、時間範圍或關鍵字撈回歸檔的逐字稿。 |
|
|
124
|
+
| `archiveTranscript(session, messages)` | 把宿主訊息寫入逐字稿歸檔。 |
|
|
125
|
+
| `compactSessionFile(session, opts?)` | 有 `SessionFileAccess` 時壓縮宿主 session 檔。 |
|
|
126
|
+
| `gwm.on/off/status/update` | Global Working Memory(目標追蹤 + 漂移偵測)。 |
|
|
127
|
+
| `maintenance.runCleanup()` / `runNightConsolidation()` | 手動觸發維護。 |
|
|
128
|
+
|
|
129
|
+
`MemoryRiverConfig` 只有 `dataDir` 與 `ramDir` 必填,其餘(`embedding`、`retrieval`、`cleanup`、`health`、`hooks`、`causalEngine`、`concentration`、`autoRecall`、`driftThreshold`…)皆可選,與預設值合併。
|
|
130
|
+
|
|
131
|
+
## 技能膠囊 v2
|
|
132
|
+
|
|
133
|
+
技能是 agent **顯式儲存**的程序 — 系統永遠不會自動生成技能:
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
await river.skills.save({
|
|
137
|
+
name: 'git-release',
|
|
138
|
+
summary: '照標準流程打 tag 出 release',
|
|
139
|
+
triggers: ['發版', 'release'],
|
|
140
|
+
steps: ['跑完整測試', 'git tag -s vX.Y.Z', 'git push --tags', '寫 release notes'],
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
- **漸進式揭露**:`assembleContext` 只注入一行索引(`【git-release】觸發: … → skill_load("git-release")`);完整步驟在 agent 呼叫 `skills.load` 之前是零 token 成本。
|
|
145
|
+
- **誠實的使用統計**:只有 `load` 會 +1 `usageCount` — 被注入不算被使用。
|
|
146
|
+
- **生命週期**:技能的衰減速度是一般記憶的 1/4,每次 load 回血;沒人用的技能會慢慢淡出,不會永遠佔著索引名額。
|
|
147
|
+
- **確定性品質閘**:格式不合的定義會被拒收,所有違規一次列完 — 不用 LLM 評審、不做沉默修正。
|
|
148
|
+
|
|
149
|
+
## 依賴 Ports
|
|
150
|
+
|
|
151
|
+
外部服務由宿主擁有。必填:`embedder`、`llm`。可選:`logger`、`notifier`、`sessionFiles`。
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
interface EmbeddingProvider {
|
|
155
|
+
embed(text: string, mode?: 'store' | 'query'): Promise<number[]>;
|
|
156
|
+
embedBatch(texts: string[]): Promise<number[][]>;
|
|
157
|
+
getDimensions(): number;
|
|
158
|
+
healthCheck?(): Promise<boolean>;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
interface LlmClient {
|
|
162
|
+
generate(prompt: string, opts?: { purpose?: string; maxTokens?: number }): Promise<string>;
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
供應商選擇、重試、fallback、限流都屬於你的 `LlmClient` — core 刻意不內建多供應商 fallback 鏈。
|
|
167
|
+
|
|
168
|
+
`Logger` 預設走 console,`Notifier` 預設靜默。沒接 `SessionFileAccess` 時,逐字稿歸檔與 rehydrate 照常運作,只有 `compactSessionFile()` 變 no-op。
|
|
169
|
+
|
|
170
|
+
## 移植到別的 agent 宿主
|
|
171
|
+
|
|
172
|
+
1. 準備可寫的 `dataDir` + `ramDir`。
|
|
173
|
+
2. 實作 `EmbeddingProvider`(或直接用 `OllamaEmbedding`)。
|
|
174
|
+
3. 實作 `LlmClient`(任何 OpenAI 相容端點約 20 行)。
|
|
175
|
+
4. `createMemoryRiver(...)`,宿主啟動時 `start()`、關閉時 `stop()`。
|
|
176
|
+
5. 把 `remember` / `recall`(可加 `skills.save` / `skills.load`)掛成宿主的 tool。
|
|
177
|
+
|
|
178
|
+
到這裡就是一個能用的整合 — `example-cli` 就是這五步,總共約 110 行。第 6–9 步是可選的進階層:對話過 `assembleContext`、歸檔逐字稿供 `rehydrate`、接 `SessionFileAccess` 做 session 檔壓縮、接 `Logger`/`Notifier`。
|
|
179
|
+
|
|
180
|
+
## 持久性說明
|
|
181
|
+
|
|
182
|
+
LanceDB 雙層儲存 + WAL。insert 在回應前先落 WAL;replay 冪等,失敗會保留 log 供下次重試。本套件**不**宣稱 exactly-once recovery 或零資料遺失 — 請把資料目錄當應用程式狀態看待,照你宿主的標準備份。
|
|
183
|
+
|
|
184
|
+
## 授權
|
|
185
|
+
|
|
186
|
+
Apache-2.0 © 2026 Hsi431。寬鬆條款,自由使用、修改、嵌入、出貨。詳見 repo 根目錄的 [LICENSE](../../LICENSE)。
|