@moxxy/plugin-memory 0.27.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 +21 -0
- package/dist/consolidate.d.ts +62 -0
- package/dist/consolidate.d.ts.map +1 -0
- package/dist/consolidate.js +417 -0
- package/dist/consolidate.js.map +1 -0
- package/dist/embedding-cache.d.ts +32 -0
- package/dist/embedding-cache.d.ts.map +1 -0
- package/dist/embedding-cache.js +146 -0
- package/dist/embedding-cache.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +217 -0
- package/dist/index.js.map +1 -0
- package/dist/parse.d.ts +5 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +9 -0
- package/dist/parse.js.map +1 -0
- package/dist/stm.d.ts +20 -0
- package/dist/stm.d.ts.map +1 -0
- package/dist/stm.js +38 -0
- package/dist/stm.js.map +1 -0
- package/dist/store/io.d.ts +13 -0
- package/dist/store/io.d.ts.map +1 -0
- package/dist/store/io.js +124 -0
- package/dist/store/io.js.map +1 -0
- package/dist/store/search.d.ts +10 -0
- package/dist/store/search.d.ts.map +1 -0
- package/dist/store/search.js +160 -0
- package/dist/store/search.js.map +1 -0
- package/dist/store/types.d.ts +33 -0
- package/dist/store/types.d.ts.map +1 -0
- package/dist/store/types.js +11 -0
- package/dist/store/types.js.map +1 -0
- package/dist/store.d.ts +95 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +220 -0
- package/dist/store.js.map +1 -0
- package/dist/tfidf.d.ts +29 -0
- package/dist/tfidf.d.ts.map +1 -0
- package/dist/tfidf.js +103 -0
- package/dist/tfidf.js.map +1 -0
- package/package.json +62 -0
- package/src/consolidate-nudge.test.ts +98 -0
- package/src/consolidate.test.ts +328 -0
- package/src/consolidate.ts +535 -0
- package/src/discovery.test.ts +33 -0
- package/src/embedding-cache.test.ts +268 -0
- package/src/embedding-cache.ts +156 -0
- package/src/index.test.ts +67 -0
- package/src/index.ts +247 -0
- package/src/parse.ts +12 -0
- package/src/stm.test.ts +69 -0
- package/src/stm.ts +48 -0
- package/src/store/io.test.ts +100 -0
- package/src/store/io.ts +138 -0
- package/src/store/search.test.ts +185 -0
- package/src/store/search.ts +197 -0
- package/src/store/types.ts +23 -0
- package/src/store.test.ts +186 -0
- package/src/store.ts +292 -0
- package/src/tfidf.test.ts +59 -0
- package/src/tfidf.ts +105 -0
- package/src/vector-recall.test.ts +88 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { writeFileAtomic } from '@moxxy/sdk/server';
|
|
5
|
+
const INDEX_FILE = '.embeddings.json';
|
|
6
|
+
const INDEX_VERSION = 1;
|
|
7
|
+
/**
|
|
8
|
+
* Persists computed embeddings to `<memoryDir>/.embeddings.json` keyed by
|
|
9
|
+
* content hash. The cache is invalidated when the embedder name OR its
|
|
10
|
+
* dimensionality changes — a name alone is too coarse (e.g. the OpenAI embedder
|
|
11
|
+
* reports a fixed name across models/`dimensions` settings, so a 1536→3072
|
|
12
|
+
* model switch must invalidate on the dim mismatch or recall compares
|
|
13
|
+
* incomparable vectors).
|
|
14
|
+
*/
|
|
15
|
+
export class EmbeddingIndex {
|
|
16
|
+
dir;
|
|
17
|
+
embedderName;
|
|
18
|
+
dim;
|
|
19
|
+
cache = new Map();
|
|
20
|
+
dirty = false;
|
|
21
|
+
loaded = false;
|
|
22
|
+
constructor(dir, embedderName, dim) {
|
|
23
|
+
this.dir = dir;
|
|
24
|
+
this.embedderName = embedderName;
|
|
25
|
+
this.dim = dim;
|
|
26
|
+
}
|
|
27
|
+
static hash(text) {
|
|
28
|
+
return createHash('sha256').update(text).digest('hex').slice(0, 24);
|
|
29
|
+
}
|
|
30
|
+
get filePath() {
|
|
31
|
+
return path.join(this.dir, INDEX_FILE);
|
|
32
|
+
}
|
|
33
|
+
async load() {
|
|
34
|
+
// Read the on-disk cache at most once per instance. The store memoizes this
|
|
35
|
+
// index for its lifetime and is the single writer (flush() keeps disk in
|
|
36
|
+
// sync for our own writes), so re-reading + re-parsing the whole file on
|
|
37
|
+
// every recall is pure overhead — the in-memory Map is already authoritative.
|
|
38
|
+
if (this.loaded)
|
|
39
|
+
return;
|
|
40
|
+
let raw;
|
|
41
|
+
try {
|
|
42
|
+
raw = await fs.readFile(this.filePath, 'utf8');
|
|
43
|
+
}
|
|
44
|
+
catch (err) {
|
|
45
|
+
if (!isEnoent(err))
|
|
46
|
+
throw err;
|
|
47
|
+
// No file on disk yet — still treat as loaded so subsequent recalls don't
|
|
48
|
+
// re-stat. This process is the single writer; flush() creates the file.
|
|
49
|
+
this.loaded = true;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// The cache is a pure optimization: a corrupt/garbled/half-synced file
|
|
53
|
+
// (truncated JSON, manual edit, partial cloud-drive sync, schema drift) must
|
|
54
|
+
// degrade to a COLD cache, never permanently break every recall. Parse and
|
|
55
|
+
// shape-check defensively; on any failure, log and start empty.
|
|
56
|
+
this.loaded = true;
|
|
57
|
+
let parsed;
|
|
58
|
+
try {
|
|
59
|
+
parsed = JSON.parse(raw);
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
console.warn(`[plugin-memory] ignoring corrupt embedding cache (${this.filePath}): ${String(err)}`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (!isValidIndexFile(parsed))
|
|
66
|
+
return; // malformed shape → cold cache
|
|
67
|
+
if (parsed.version !== INDEX_VERSION)
|
|
68
|
+
return; // unknown format, ignore
|
|
69
|
+
if (parsed.embedder !== this.embedderName)
|
|
70
|
+
return; // embedder changed, invalidate
|
|
71
|
+
// Dim mismatch (incl. an old file written before dim was tracked) → the
|
|
72
|
+
// vectors are a different dimensionality; invalidate rather than mix them.
|
|
73
|
+
if (this.dim !== undefined && parsed.dim !== this.dim)
|
|
74
|
+
return;
|
|
75
|
+
for (const [name, entry] of Object.entries(parsed.entries)) {
|
|
76
|
+
if (isValidIndexEntry(entry))
|
|
77
|
+
this.cache.set(name, entry);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* For a `(name, body)` pair, return either the cached vector (if the body
|
|
82
|
+
* hash matches) or `null` (miss). Callers re-embed the misses and call
|
|
83
|
+
* `set()` with the fresh vectors.
|
|
84
|
+
*/
|
|
85
|
+
lookup(name, body) {
|
|
86
|
+
const entry = this.cache.get(name);
|
|
87
|
+
if (!entry)
|
|
88
|
+
return null;
|
|
89
|
+
if (entry.hash !== EmbeddingIndex.hash(body))
|
|
90
|
+
return null;
|
|
91
|
+
return entry.vector;
|
|
92
|
+
}
|
|
93
|
+
set(name, body, vector) {
|
|
94
|
+
const hash = EmbeddingIndex.hash(body);
|
|
95
|
+
const existing = this.cache.get(name);
|
|
96
|
+
if (existing && existing.hash === hash)
|
|
97
|
+
return;
|
|
98
|
+
this.cache.set(name, { hash, vector });
|
|
99
|
+
this.dirty = true;
|
|
100
|
+
}
|
|
101
|
+
/** Drop entries that no longer correspond to existing memories. */
|
|
102
|
+
prune(currentNames) {
|
|
103
|
+
const wanted = new Set(currentNames);
|
|
104
|
+
for (const name of [...this.cache.keys()]) {
|
|
105
|
+
if (!wanted.has(name)) {
|
|
106
|
+
this.cache.delete(name);
|
|
107
|
+
this.dirty = true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async flush() {
|
|
112
|
+
if (!this.dirty)
|
|
113
|
+
return;
|
|
114
|
+
const data = {
|
|
115
|
+
version: INDEX_VERSION,
|
|
116
|
+
embedder: this.embedderName,
|
|
117
|
+
...(this.dim !== undefined ? { dim: this.dim } : {}),
|
|
118
|
+
entries: Object.fromEntries(this.cache),
|
|
119
|
+
};
|
|
120
|
+
await writeFileAtomic(this.filePath, JSON.stringify(data), { mode: 0o600 });
|
|
121
|
+
this.dirty = false;
|
|
122
|
+
}
|
|
123
|
+
get size() {
|
|
124
|
+
return this.cache.size;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function isEnoent(err) {
|
|
128
|
+
return err instanceof Error && 'code' in err && err.code === 'ENOENT';
|
|
129
|
+
}
|
|
130
|
+
/** Structural guard so a valid-JSON-but-wrong-shape file (e.g. a missing
|
|
131
|
+
* `entries`) degrades to a cold cache instead of throwing in load(). */
|
|
132
|
+
function isValidIndexFile(value) {
|
|
133
|
+
if (typeof value !== 'object' || value === null)
|
|
134
|
+
return false;
|
|
135
|
+
const v = value;
|
|
136
|
+
return typeof v.entries === 'object' && v.entries !== null;
|
|
137
|
+
}
|
|
138
|
+
function isValidIndexEntry(value) {
|
|
139
|
+
if (typeof value !== 'object' || value === null)
|
|
140
|
+
return false;
|
|
141
|
+
const e = value;
|
|
142
|
+
return (typeof e.hash === 'string' &&
|
|
143
|
+
Array.isArray(e.vector) &&
|
|
144
|
+
e.vector.every((n) => typeof n === 'number'));
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=embedding-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding-cache.js","sourceRoot":"","sources":["../src/embedding-cache.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type Plugin } from '@moxxy/sdk';
|
|
2
|
+
import { MemoryStore, type MemoryStoreOptions } from './store.js';
|
|
3
|
+
export { MemoryStore, memoryTypeSchema, memoryFrontmatterSchema, defaultMemoryDir, type MemoryEntry, type MemoryFrontmatter, type MemoryStoreOptions, type MemoryType, type RankedMemory, type RecallMode, } from './store.js';
|
|
4
|
+
export { parseMdFile, parseFrontmatter, renderFrontmatter } from './parse.js';
|
|
5
|
+
export { recentExchanges, summarizeSession, type SessionFact } from './stm.js';
|
|
6
|
+
export { TfIdfEmbedder, cosineSimilarity, tokenize } from './tfidf.js';
|
|
7
|
+
export { EmbeddingIndex } from './embedding-cache.js';
|
|
8
|
+
export { planConsolidation, consolidateMemory, buildMemoryConsolidatePlugin, memoryConsolidatePlugin, type ConsolidatePlan, type ConsolidateOptions, type ConsolidationOutcome, } from './consolidate.js';
|
|
9
|
+
export interface BuildMemoryPluginOptions extends MemoryStoreOptions {
|
|
10
|
+
}
|
|
11
|
+
export declare function buildMemoryPlugin(opts?: BuildMemoryPluginOptions): {
|
|
12
|
+
plugin: Plugin;
|
|
13
|
+
store: MemoryStore;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Discovery-loadable instance: the WHOLE memory feature (long-term store +
|
|
17
|
+
* memory_save/recall/… tools + the tfidf embedder + memory_consolidate and
|
|
18
|
+
* its nudge hooks) as ONE plugin, so the package unbundles cleanly — the
|
|
19
|
+
* loader takes a single default export per package. Composition over the
|
|
20
|
+
* existing builders:
|
|
21
|
+
* - the store's embedder resolves LAZILY from the host-published
|
|
22
|
+
* 'embedders' registry service (captured in onInit, read on first
|
|
23
|
+
* recall), replacing the bootstrap closure the CLI used to inject;
|
|
24
|
+
* - our onInit registers the 'memory' service FIRST, then runs
|
|
25
|
+
* consolidate's onInit, which resolves it — same ordering the two
|
|
26
|
+
* separate builtin entries relied on.
|
|
27
|
+
* `buildMemoryPlugin` stays for hosts/tests that inject their own store.
|
|
28
|
+
*/
|
|
29
|
+
export declare const memoryPlugin: Plugin;
|
|
30
|
+
export default memoryPlugin;
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+C,KAAK,MAAM,EAAE,MAAM,YAAY,CAAC;AACtF,OAAO,EAAE,WAAW,EAAoB,KAAK,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGpF,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,uBAAuB,EACvB,gBAAgB,EAChB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,UAAU,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,4BAA4B,EAC5B,uBAAuB,EACvB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,GAC1B,MAAM,kBAAkB,CAAC;AAG1B,MAAM,WAAW,wBAAyB,SAAQ,kBAAkB;CAAG;AAEvE,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,wBAA6B,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,CAuK7G;AAGD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY,EAAE,MA0BvB,CAAC;AAGL,eAAe,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { defineTool, defineEmbedder, definePlugin, z } from '@moxxy/sdk';
|
|
2
|
+
import { MemoryStore, memoryTypeSchema } from './store.js';
|
|
3
|
+
import { TfIdfEmbedder } from './tfidf.js';
|
|
4
|
+
export { MemoryStore, memoryTypeSchema, memoryFrontmatterSchema, defaultMemoryDir, } from './store.js';
|
|
5
|
+
export { parseMdFile, parseFrontmatter, renderFrontmatter } from './parse.js';
|
|
6
|
+
export { recentExchanges, summarizeSession } from './stm.js';
|
|
7
|
+
export { TfIdfEmbedder, cosineSimilarity, tokenize } from './tfidf.js';
|
|
8
|
+
export { EmbeddingIndex } from './embedding-cache.js';
|
|
9
|
+
export { planConsolidation, consolidateMemory, buildMemoryConsolidatePlugin, memoryConsolidatePlugin, } from './consolidate.js';
|
|
10
|
+
import { memoryConsolidatePlugin as memoryConsolidatePluginRef } from './consolidate.js';
|
|
11
|
+
export function buildMemoryPlugin(opts = {}) {
|
|
12
|
+
const store = new MemoryStore(opts);
|
|
13
|
+
const plugin = definePlugin({
|
|
14
|
+
name: '@moxxy/plugin-memory',
|
|
15
|
+
version: '0.0.0',
|
|
16
|
+
// Publish the long-term store on the inter-plugin service registry so the
|
|
17
|
+
// sibling @moxxy/memory-consolidate plugin can resolve it in its own onInit
|
|
18
|
+
// instead of being hand-built with the store — the seam that lets both be
|
|
19
|
+
// discovery-loaded. memory-consolidate is registered after this plugin, so
|
|
20
|
+
// this onInit runs first.
|
|
21
|
+
hooks: {
|
|
22
|
+
onInit: (ctx) => {
|
|
23
|
+
ctx.services.register('memory', store);
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
// The zero-dep TF-IDF embedder, contributed as a selectable embedder so it
|
|
27
|
+
// sits in the same registry as openai/transformers/custom ones.
|
|
28
|
+
embedders: [
|
|
29
|
+
defineEmbedder({
|
|
30
|
+
name: 'tfidf',
|
|
31
|
+
displayName: 'TF-IDF (built-in, zero-dep)',
|
|
32
|
+
createClient: () => new TfIdfEmbedder(),
|
|
33
|
+
}),
|
|
34
|
+
],
|
|
35
|
+
tools: [
|
|
36
|
+
defineTool({
|
|
37
|
+
name: 'memory_save',
|
|
38
|
+
description: 'Persist a memory to long-term storage. Use sparingly — only for facts/preferences/' +
|
|
39
|
+
'project context that would help you in future sessions. Keep the body terse.',
|
|
40
|
+
inputSchema: z.object({
|
|
41
|
+
name: z.string().min(1).regex(/^[a-z0-9][a-z0-9-]*$/, 'name must be slug-like'),
|
|
42
|
+
type: memoryTypeSchema,
|
|
43
|
+
description: z.string().min(1).max(280),
|
|
44
|
+
body: z.string().min(1).max(4000),
|
|
45
|
+
tags: z.array(z.string().min(1)).optional(),
|
|
46
|
+
}),
|
|
47
|
+
permission: { action: 'prompt' },
|
|
48
|
+
isolation: {
|
|
49
|
+
capabilities: {
|
|
50
|
+
fs: { read: ['~/.moxxy/memory/**'], write: ['~/.moxxy/memory/**'] },
|
|
51
|
+
net: { mode: 'none' },
|
|
52
|
+
timeMs: 5_000,
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
handler: async ({ name, type, description, body, tags }) => {
|
|
56
|
+
const saved = await store.save({ name, type, description, body, tags });
|
|
57
|
+
const cap = await store.capStatus();
|
|
58
|
+
return {
|
|
59
|
+
name: saved.frontmatter.name,
|
|
60
|
+
path: saved.path,
|
|
61
|
+
// Warn-only soft cap: the save succeeded, but tell the model the
|
|
62
|
+
// store is overgrown so it consolidates / forgets stale entries.
|
|
63
|
+
...(cap.over
|
|
64
|
+
? {
|
|
65
|
+
warning: `memory store holds ${cap.count} entries (soft cap ${cap.max}). ` +
|
|
66
|
+
`Nothing was evicted — consider consolidating related memories or using memory_forget on stale ones.`,
|
|
67
|
+
}
|
|
68
|
+
: {}),
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
}),
|
|
72
|
+
defineTool({
|
|
73
|
+
name: 'memory_recall',
|
|
74
|
+
description: 'Search long-term memory by free-text query. Uses vector similarity (TF-IDF by default, ' +
|
|
75
|
+
'or a configured EmbeddingProvider) when mode is "auto" or "vector". Returns the most ' +
|
|
76
|
+
'relevant entries with their full bodies.',
|
|
77
|
+
inputSchema: z.object({
|
|
78
|
+
query: z.string().min(1),
|
|
79
|
+
limit: z.number().int().min(1).max(20).optional().default(5),
|
|
80
|
+
type: memoryTypeSchema.optional(),
|
|
81
|
+
mode: z.enum(['auto', 'vector', 'keyword']).optional().default('auto'),
|
|
82
|
+
}),
|
|
83
|
+
isolation: {
|
|
84
|
+
capabilities: {
|
|
85
|
+
fs: { read: ['~/.moxxy/memory/**'] },
|
|
86
|
+
// Vector recall may call out to an EmbeddingProvider (OpenAI,
|
|
87
|
+
// local transformers, …). The inproc isolator can't enforce
|
|
88
|
+
// this; a stronger isolator should constrain to the actual
|
|
89
|
+
// configured embedder's host.
|
|
90
|
+
net: { mode: 'any' },
|
|
91
|
+
timeMs: 15_000,
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
handler: async ({ query, limit, type, mode }) => {
|
|
95
|
+
const matches = await store.recall(query, { limit, type, mode });
|
|
96
|
+
return matches.map(({ entry, score }) => ({
|
|
97
|
+
name: entry.frontmatter.name,
|
|
98
|
+
type: entry.frontmatter.type,
|
|
99
|
+
description: entry.frontmatter.description,
|
|
100
|
+
body: entry.body,
|
|
101
|
+
score,
|
|
102
|
+
}));
|
|
103
|
+
},
|
|
104
|
+
}),
|
|
105
|
+
defineTool({
|
|
106
|
+
name: 'memory_list',
|
|
107
|
+
description: 'List all stored memories (name + type + description, no body).',
|
|
108
|
+
inputSchema: z.object({ type: memoryTypeSchema.optional() }),
|
|
109
|
+
isolation: {
|
|
110
|
+
capabilities: {
|
|
111
|
+
fs: { read: ['~/.moxxy/memory/**'] },
|
|
112
|
+
net: { mode: 'none' },
|
|
113
|
+
timeMs: 5_000,
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
handler: async ({ type }) => {
|
|
117
|
+
const entries = await store.list(type);
|
|
118
|
+
return entries.map((e) => ({
|
|
119
|
+
name: e.frontmatter.name,
|
|
120
|
+
type: e.frontmatter.type,
|
|
121
|
+
description: e.frontmatter.description,
|
|
122
|
+
tags: e.frontmatter.tags ?? [],
|
|
123
|
+
}));
|
|
124
|
+
},
|
|
125
|
+
}),
|
|
126
|
+
defineTool({
|
|
127
|
+
name: 'memory_forget',
|
|
128
|
+
description: 'Delete a memory by name. Use only when the memory is incorrect or no longer relevant.',
|
|
129
|
+
// Slug-only name: the inproc isolator does NOT enforce the fs.write glob,
|
|
130
|
+
// so this Zod guard is the sole defense against a path-traversal `name`
|
|
131
|
+
// (e.g. '../../vault') reaching fs.unlink. Mirror memory_save's regex.
|
|
132
|
+
inputSchema: z.object({
|
|
133
|
+
name: z.string().min(1).max(120).regex(/^[a-z0-9][a-z0-9-]*$/, 'name must be slug-like'),
|
|
134
|
+
}),
|
|
135
|
+
permission: { action: 'prompt' },
|
|
136
|
+
isolation: {
|
|
137
|
+
capabilities: {
|
|
138
|
+
fs: { read: ['~/.moxxy/memory/**'], write: ['~/.moxxy/memory/**'] },
|
|
139
|
+
net: { mode: 'none' },
|
|
140
|
+
timeMs: 5_000,
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
handler: async ({ name }) => {
|
|
144
|
+
const removed = await store.forget(name);
|
|
145
|
+
return removed ? `forgot ${name}` : `not found: ${name}`;
|
|
146
|
+
},
|
|
147
|
+
}),
|
|
148
|
+
defineTool({
|
|
149
|
+
name: 'memory_update',
|
|
150
|
+
description: 'Update an existing memory in place. createdAt is preserved; updatedAt bumps.',
|
|
151
|
+
inputSchema: z.object({
|
|
152
|
+
// Slug-only: see memory_forget — the schema is the only traversal guard.
|
|
153
|
+
name: z.string().min(1).max(120).regex(/^[a-z0-9][a-z0-9-]*$/, 'name must be slug-like'),
|
|
154
|
+
description: z.string().min(1).max(280).optional(),
|
|
155
|
+
body: z.string().min(1).max(4000).optional(),
|
|
156
|
+
tags: z.array(z.string().min(1)).optional(),
|
|
157
|
+
}),
|
|
158
|
+
permission: { action: 'prompt' },
|
|
159
|
+
isolation: {
|
|
160
|
+
capabilities: {
|
|
161
|
+
fs: { read: ['~/.moxxy/memory/**'], write: ['~/.moxxy/memory/**'] },
|
|
162
|
+
net: { mode: 'none' },
|
|
163
|
+
timeMs: 5_000,
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
handler: async ({ name, description, body, tags }) => {
|
|
167
|
+
const updated = await store.update(name, { description, body, tags });
|
|
168
|
+
if (!updated)
|
|
169
|
+
throw new Error(`memory '${name}' not found`);
|
|
170
|
+
return { name: updated.frontmatter.name, updatedAt: updated.frontmatter.updatedAt };
|
|
171
|
+
},
|
|
172
|
+
}),
|
|
173
|
+
],
|
|
174
|
+
});
|
|
175
|
+
return { plugin, store };
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Discovery-loadable instance: the WHOLE memory feature (long-term store +
|
|
179
|
+
* memory_save/recall/… tools + the tfidf embedder + memory_consolidate and
|
|
180
|
+
* its nudge hooks) as ONE plugin, so the package unbundles cleanly — the
|
|
181
|
+
* loader takes a single default export per package. Composition over the
|
|
182
|
+
* existing builders:
|
|
183
|
+
* - the store's embedder resolves LAZILY from the host-published
|
|
184
|
+
* 'embedders' registry service (captured in onInit, read on first
|
|
185
|
+
* recall), replacing the bootstrap closure the CLI used to inject;
|
|
186
|
+
* - our onInit registers the 'memory' service FIRST, then runs
|
|
187
|
+
* consolidate's onInit, which resolves it — same ordering the two
|
|
188
|
+
* separate builtin entries relied on.
|
|
189
|
+
* `buildMemoryPlugin` stays for hosts/tests that inject their own store.
|
|
190
|
+
*/
|
|
191
|
+
export const memoryPlugin = (() => {
|
|
192
|
+
let embeddersReg = null;
|
|
193
|
+
const { plugin: base } = buildMemoryPlugin({
|
|
194
|
+
// The registry hands back an EmbedderClient-compatible instance; the
|
|
195
|
+
// structural cast keeps this file free of a core import.
|
|
196
|
+
embedder: () => (embeddersReg?.tryGetActive() ?? null),
|
|
197
|
+
});
|
|
198
|
+
const consolidate = memoryConsolidatePluginRef;
|
|
199
|
+
return definePlugin({
|
|
200
|
+
name: '@moxxy/plugin-memory',
|
|
201
|
+
version: '0.0.0',
|
|
202
|
+
...(base.embedders ? { embedders: base.embedders } : {}),
|
|
203
|
+
tools: [...(base.tools ?? []), ...(consolidate.tools ?? [])],
|
|
204
|
+
hooks: {
|
|
205
|
+
...consolidate.hooks,
|
|
206
|
+
onInit: async (ctx) => {
|
|
207
|
+
embeddersReg =
|
|
208
|
+
ctx.services.get('embedders') ?? null;
|
|
209
|
+
await base.hooks?.onInit?.(ctx);
|
|
210
|
+
await consolidate.hooks?.onInit?.(ctx);
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
});
|
|
214
|
+
})();
|
|
215
|
+
// Discovery entry: `createPluginLoader` requires a default Plugin export.
|
|
216
|
+
export default memoryPlugin;
|
|
217
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/parse.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { parseFrontmatterFile, type ParsedFrontmatter } from '@moxxy/sdk';
|
|
2
|
+
export type ParsedFile = ParsedFrontmatter;
|
|
3
|
+
export declare const parseMdFile: typeof parseFrontmatterFile;
|
|
4
|
+
export { parseFrontmatter, renderFrontmatter } from '@moxxy/sdk';
|
|
5
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,oBAAoB,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE1E,MAAM,MAAM,UAAU,GAAG,iBAAiB,CAAC;AAE3C,eAAO,MAAM,WAAW,6BAAuB,CAAC;AAEhD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/parse.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// The MD+frontmatter parser now lives canonically in @moxxy/sdk
|
|
2
|
+
// (`parseFrontmatterFile`/`parseFrontmatter`/`renderFrontmatter`), shared with
|
|
3
|
+
// @moxxy/core so the previously-copy-pasted copies can't diverge. This module
|
|
4
|
+
// keeps the historical `parseMdFile`/`ParsedFile` names as thin re-exports.
|
|
5
|
+
// (The plugin already depends on @moxxy/sdk, so this stays leaf-only.)
|
|
6
|
+
import { parseFrontmatterFile } from '@moxxy/sdk';
|
|
7
|
+
export const parseMdFile = parseFrontmatterFile;
|
|
8
|
+
export { parseFrontmatter, renderFrontmatter } from '@moxxy/sdk';
|
|
9
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,+EAA+E;AAC/E,8EAA8E;AAC9E,4EAA4E;AAC5E,uEAAuE;AACvE,OAAO,EAAE,oBAAoB,EAA0B,MAAM,YAAY,CAAC;AAI1E,MAAM,CAAC,MAAM,WAAW,GAAG,oBAAoB,CAAC;AAEhD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/stm.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { EventLogReader } from '@moxxy/sdk';
|
|
2
|
+
export interface SessionFact {
|
|
3
|
+
readonly turnId: string;
|
|
4
|
+
readonly seq: number;
|
|
5
|
+
readonly source: 'user' | 'assistant';
|
|
6
|
+
readonly text: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Short-term memory helpers. STM is the event log itself — these selectors
|
|
10
|
+
* just project a useful view over it.
|
|
11
|
+
*/
|
|
12
|
+
export declare function recentExchanges(log: EventLogReader, n?: number): ReadonlyArray<SessionFact>;
|
|
13
|
+
export declare function summarizeSession(log: EventLogReader): {
|
|
14
|
+
turns: number;
|
|
15
|
+
toolCalls: number;
|
|
16
|
+
errors: number;
|
|
17
|
+
skillsCreated: number;
|
|
18
|
+
pluginsLoaded: number;
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=stm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stm.d.ts","sourceRoot":"","sources":["../src/stm.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,CAAC;IACtC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AAEH,wBAAgB,eAAe,CAAC,GAAG,EAAE,cAAc,EAAE,CAAC,SAAI,GAAG,aAAa,CAAC,WAAW,CAAC,CAUtF;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,cAAc,GAAG;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACvB,CAeA"}
|
package/dist/stm.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Short-term memory helpers. STM is the event log itself — these selectors
|
|
3
|
+
* just project a useful view over it.
|
|
4
|
+
*/
|
|
5
|
+
export function recentExchanges(log, n = 5) {
|
|
6
|
+
const out = [];
|
|
7
|
+
for (const e of log.slice()) {
|
|
8
|
+
if (e.type === 'user_prompt') {
|
|
9
|
+
out.push({ turnId: e.turnId, seq: e.seq, source: 'user', text: e.text });
|
|
10
|
+
}
|
|
11
|
+
else if (e.type === 'assistant_message') {
|
|
12
|
+
out.push({ turnId: e.turnId, seq: e.seq, source: 'assistant', text: e.content });
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return out.slice(-n);
|
|
16
|
+
}
|
|
17
|
+
export function summarizeSession(log) {
|
|
18
|
+
const seenTurns = new Set();
|
|
19
|
+
let toolCalls = 0;
|
|
20
|
+
let errors = 0;
|
|
21
|
+
let skillsCreated = 0;
|
|
22
|
+
let pluginsLoaded = 0;
|
|
23
|
+
for (const e of log.slice()) {
|
|
24
|
+
seenTurns.add(e.turnId);
|
|
25
|
+
if (e.type === 'tool_call_requested')
|
|
26
|
+
toolCalls += 1;
|
|
27
|
+
if (e.type === 'error')
|
|
28
|
+
errors += 1;
|
|
29
|
+
if (e.type === 'skill_created')
|
|
30
|
+
skillsCreated += 1;
|
|
31
|
+
if (e.type === 'plugin_registered')
|
|
32
|
+
pluginsLoaded += 1;
|
|
33
|
+
if (e.type === 'plugin_unregistered')
|
|
34
|
+
pluginsLoaded -= 1;
|
|
35
|
+
}
|
|
36
|
+
return { turns: seenTurns.size, toolCalls, errors, skillsCreated, pluginsLoaded };
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=stm.js.map
|
package/dist/stm.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stm.js","sourceRoot":"","sources":["../src/stm.ts"],"names":[],"mappings":"AASA;;;GAGG;AAEH,MAAM,UAAU,eAAe,CAAC,GAAmB,EAAE,CAAC,GAAG,CAAC;IACxD,MAAM,GAAG,GAAkB,EAAE,CAAC;IAC9B,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC;QAC5B,IAAI,CAAC,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAC7B,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QAC3E,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;YAC1C,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACnF,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACvB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAmB;IAOlD,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IACpC,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,KAAK,EAAE,EAAE,CAAC;QAC5B,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACxB,IAAI,CAAC,CAAC,IAAI,KAAK,qBAAqB;YAAE,SAAS,IAAI,CAAC,CAAC;QACrD,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO;YAAE,MAAM,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,CAAC,IAAI,KAAK,eAAe;YAAE,aAAa,IAAI,CAAC,CAAC;QACnD,IAAI,CAAC,CAAC,IAAI,KAAK,mBAAmB;YAAE,aAAa,IAAI,CAAC,CAAC;QACvD,IAAI,CAAC,CAAC,IAAI,KAAK,qBAAqB;YAAE,aAAa,IAAI,CAAC,CAAC;IAC3D,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,SAAS,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC;AACpF,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type MemoryEntry, type MemoryFrontmatter, type MemoryType } from './types.js';
|
|
2
|
+
export declare function safeRead(filePath: string): Promise<{
|
|
3
|
+
frontmatter: MemoryFrontmatter;
|
|
4
|
+
body: string;
|
|
5
|
+
} | null>;
|
|
6
|
+
export declare function isEnoent(err: unknown): boolean;
|
|
7
|
+
export declare function listEntries(dir: string, filterType?: MemoryType): Promise<ReadonlyArray<MemoryEntry>>;
|
|
8
|
+
export declare function readEntry(filePath: string): Promise<MemoryEntry | null>;
|
|
9
|
+
/** What the MEMORY.md index needs per entry — no body, so the incremental
|
|
10
|
+
* index cache in MemoryStore can feed it without re-reading entry files. */
|
|
11
|
+
export type IndexRow = Pick<MemoryEntry, 'frontmatter' | 'path'>;
|
|
12
|
+
export declare function writeIndex(dir: string, entries: ReadonlyArray<IndexRow>): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=io.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../src/store/io.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EAChB,MAAM,YAAY,CAAC;AAEpB,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,WAAW,EAAE,iBAAiB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAelE;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAE9C;AAWD,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,UAAU,CAAC,EAAE,UAAU,GACtB,OAAO,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAmDrC;AAED,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAW7E;AAED;6EAC6E;AAC7E,MAAM,MAAM,QAAQ,GAAG,IAAI,CAAC,WAAW,EAAE,aAAa,GAAG,MAAM,CAAC,CAAC;AAEjE,wBAAsB,UAAU,CAC9B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,aAAa,CAAC,QAAQ,CAAC,GAC/B,OAAO,CAAC,IAAI,CAAC,CAkBf"}
|