@lotargo/memory_plugin 1.4.620 → 1.5.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.
Files changed (35) hide show
  1. package/README.md +352 -334
  2. package/mcp-server/admin/auth.js +293 -42
  3. package/mcp-server/cli/direct_commands.js +313 -0
  4. package/mcp-server/cli/handlers/cloud_actions.js +138 -0
  5. package/mcp-server/cli/handlers/diagnostics_actions.js +107 -0
  6. package/mcp-server/cli/handlers/engine_actions.js +214 -0
  7. package/mcp-server/cli/handlers/prompt_actions.js +24 -0
  8. package/mcp-server/cli/handlers/storage_actions.js +749 -0
  9. package/mcp-server/cli/quick_stats.js +39 -0
  10. package/mcp-server/cli/ui.js +565 -0
  11. package/mcp-server/cli.js +324 -1945
  12. package/mcp-server/config/auth_store.js +178 -19
  13. package/mcp-server/config/config_manager.js +1 -0
  14. package/mcp-server/db/database.js +18 -3
  15. package/mcp-server/db/migrations.js +28 -0
  16. package/mcp-server/fact_format.js +244 -177
  17. package/mcp-server/identity.js +152 -0
  18. package/mcp-server/index.js +42 -679
  19. package/mcp-server/memory.js +50 -63
  20. package/mcp-server/prompt_manager.js +1 -1
  21. package/mcp-server/setup.js +41 -0
  22. package/mcp-server/tools/helpers.js +39 -0
  23. package/mcp-server/tools/identity_tools.js +277 -0
  24. package/mcp-server/tools/index.js +9 -0
  25. package/mcp-server/tools/memory_tools.js +506 -0
  26. package/mcp-server/tools/rag_tools.js +235 -0
  27. package/opencode-plugin/index.js +460 -48
  28. package/package.json +7 -3
  29. package/skills/using-memory/SKILL.md +31 -14
  30. package/mcp-server/benchmarks/fetch_real_corpus.js +0 -351
  31. package/mcp-server/benchmarks/gpu_profile_benchmark.js +0 -170
  32. package/mcp-server/benchmarks/quality_evaluator.js +0 -600
  33. package/mcp-server/benchmarks/run_benchmarks.js +0 -347
  34. package/mcp-server/benchmarks/stress_ingestion.js +0 -195
  35. package/mcp-server/benchmarks/test_dual_layer.js +0 -140
@@ -0,0 +1,214 @@
1
+ import { updateConfig } from "../../config/config_manager.js";
2
+ import { getModelStorageInfo } from "../../ml/model_manager.js";
3
+ import {
4
+ EMBEDDING_PRESETS,
5
+ RERANKER_PRESETS,
6
+ downloadModelWithProgress,
7
+ selectSimpleMenu,
8
+ adjustAlphaMenu,
9
+ readTextInput,
10
+ waitForEnter,
11
+ } from "../ui.js";
12
+
13
+ export async function handleEngineAction(value, config) {
14
+ switch (value) {
15
+ case "algo": {
16
+ const algoItems = [
17
+ { label: "RSF (Relative Score Fusion)", value: "rsf", info: "Normalized Score Scaling (Recommended)" },
18
+ { label: "RRF (Reciprocal Rank Fusion)", value: "rrf", info: "Rank-based Fusion (1/(k + rank))" },
19
+ { label: "Pure Semantic Search", value: "semantic_only", info: "Vector Search Only (Cosine Similarity)" },
20
+ { label: "Pure Lexical Search", value: "lexical_only", info: "BM25 Text Search Only (SQLite FTS5)" },
21
+ ];
22
+ const initialAlgoIdx = Math.max(0, algoItems.findIndex((i) => i.value === config.fusionAlgorithm));
23
+ const subRes = await selectSimpleMenu({
24
+ title: "SELECT FUSION ALGORITHM",
25
+ subtitle: "Choose how vector and keyword search scores are combined",
26
+ items: algoItems,
27
+ initialIndex: initialAlgoIdx,
28
+ });
29
+
30
+ if (subRes.action === "select") {
31
+ updateConfig({ fusionAlgorithm: subRes.value });
32
+ }
33
+ break;
34
+ }
35
+ case "alpha": {
36
+ const alphaRes = await adjustAlphaMenu(config.alpha);
37
+ if (alphaRes.action === "save") {
38
+ updateConfig({ alpha: alphaRes.value });
39
+ }
40
+ break;
41
+ }
42
+ case "embedding": {
43
+ const embItems = EMBEDDING_PRESETS.map((m) => {
44
+ const info = getModelStorageInfo(m);
45
+ let badge = "NOT DOWNLOADED";
46
+ if (info.status === "downloaded") badge = `READY (${info.sizeMB} MB)`;
47
+ else if (info.status === "partial") badge = `INCOMPLETE (${info.sizeMB} MB)`;
48
+ return { label: m, badge, value: m, info: `Model: ${m} [${badge}]` };
49
+ });
50
+ embItems.push({ label: "Custom HuggingFace Model...", value: "custom", info: "Specify custom HF model string" });
51
+ const initialEmbIdx = Math.max(0, embItems.findIndex((i) => i.value === config.embeddingModel));
52
+
53
+ const subRes = await selectSimpleMenu({
54
+ title: "SELECT EMBEDDING MODEL",
55
+ subtitle: "Dense vector extraction model via @huggingface/transformers",
56
+ items: embItems,
57
+ initialIndex: initialEmbIdx,
58
+ });
59
+
60
+ if (subRes.action === "select") {
61
+ let chosenModel = subRes.value;
62
+ if (subRes.value === "custom") {
63
+ const inputRes = await readTextInput("Enter HuggingFace Model ID", "Xenova/all-MiniLM-L6-v2");
64
+ if (inputRes.action === "submit" && inputRes.value) {
65
+ chosenModel = inputRes.value;
66
+ } else {
67
+ break;
68
+ }
69
+ }
70
+ await downloadModelWithProgress(chosenModel, "embedding");
71
+ updateConfig({ embeddingModel: chosenModel });
72
+ await waitForEnter();
73
+ }
74
+ break;
75
+ }
76
+ case "reranker": {
77
+ const rkItems = [
78
+ { label: "Disable Reranker", value: "none", info: "No cross-encoder re-ranking" },
79
+ ...RERANKER_PRESETS.filter((r) => r !== "none").map((r) => {
80
+ const info = getModelStorageInfo(r);
81
+ let badge = "NOT DOWNLOADED";
82
+ if (info.status === "downloaded") badge = `READY (${info.sizeMB} MB)`;
83
+ else if (info.status === "partial") badge = `INCOMPLETE (${info.sizeMB} MB)`;
84
+ return { label: r, badge, value: r, info: `Reranker: ${r} [${badge}]` };
85
+ }),
86
+ { label: "Custom Reranker Model...", value: "custom", info: "Specify custom HuggingFace cross-encoder model" },
87
+ ];
88
+ const currentRk = config.rerankerEnabled ? config.rerankerModel : "none";
89
+ const initialRkIdx = Math.max(0, rkItems.findIndex((i) => i.value === currentRk));
90
+
91
+ const subRes = await selectSimpleMenu({
92
+ title: "CONFIGURE RERANKER MODEL",
93
+ subtitle: "Cross-Encoder candidate re-ranking pass",
94
+ items: rkItems,
95
+ initialIndex: initialRkIdx,
96
+ });
97
+
98
+ if (subRes.action === "select") {
99
+ if (subRes.value === "none") {
100
+ updateConfig({ rerankerEnabled: false, rerankerModel: "none" });
101
+ } else {
102
+ let chosenRk = subRes.value;
103
+ if (subRes.value === "custom") {
104
+ const inputRes = await readTextInput("Enter HuggingFace Reranker Model ID", "Xenova/bge-reranker-base");
105
+ if (inputRes.action === "submit" && inputRes.value) {
106
+ chosenRk = inputRes.value;
107
+ } else {
108
+ break;
109
+ }
110
+ }
111
+ await downloadModelWithProgress(chosenRk, "reranker");
112
+ updateConfig({ rerankerEnabled: true, rerankerModel: chosenRk });
113
+ await waitForEnter();
114
+ }
115
+ }
116
+ break;
117
+ }
118
+ case "batch_size": {
119
+ const batchItems = [
120
+ { label: "Batch Size 1 (Single Item)", value: 1, info: "Process micro-chunks strictly 1 by 1" },
121
+ { label: "Batch Size 4", value: 4, info: "Small CPU batch size" },
122
+ { label: "Batch Size 8 (CPU Sweet Spot)", value: 8, info: "Optimal for CPU L3 cache" },
123
+ { label: "Batch Size 12 (Default)", value: 12, info: "Balanced CPU throughput" },
124
+ { label: "Batch Size 16", value: 16, info: "High throughput batch size" },
125
+ { label: "Batch Size 32 (Standard GPU)", value: 32, info: "Standard GPU batching" },
126
+ { label: "Batch Size 48 (High GPU)", value: 48, info: "High throughput GPU batching" },
127
+ { label: "Batch Size 64 (Ultra GPU)", value: 64, info: "Ultra-fast GPU parallel tensor execution" },
128
+ { label: "Batch Size 128 (Extreme GPU)", value: 128, info: "Massive GPU parallelism" },
129
+ { label: "Batch Size 256 (Max GPU)", value: 256, info: "Maximum batch capacity for dedicated VRAM" },
130
+ ];
131
+ const currentBatch = config.batchSize || 12;
132
+ const initialBatchIdx = Math.max(0, batchItems.findIndex((i) => i.value === currentBatch));
133
+ const subRes = await selectSimpleMenu({
134
+ title: "SELECT VECTOR BATCH SIZE",
135
+ subtitle: "Number of micro-chunks vectorized per ONNX inference pass",
136
+ items: batchItems,
137
+ initialIndex: initialBatchIdx,
138
+ });
139
+ if (subRes.action === "select") {
140
+ updateConfig({ batchSize: subRes.value });
141
+ }
142
+ break;
143
+ }
144
+ case "gpu_budget": {
145
+ const budgetItems = [
146
+ { label: "1.0M Units (Conservative ~0.8 GB VRAM)", value: 1000000, info: "Ultra-safe for 4GB-6GB GPUs or heavy background multitasking" },
147
+ { label: "2.0M Units (Balanced ~1.5 GB VRAM - Default)", value: 2000000, info: "Optimal balance between GPU throughput & safe VRAM ceiling" },
148
+ { label: "4.0M Units (Aggressive ~2.5 GB VRAM)", value: 4000000, info: "Higher GPU parallel compute for dedicated 8GB+ GPUs" },
149
+ { label: "8.0M Units (High Parallelism ~4.5 GB VRAM)", value: 8000000, info: "Maximum batching throughput for 12GB-16GB VRAM GPUs" },
150
+ { label: "16.0M Units (Extreme ~8.0 GB VRAM)", value: 16000000, info: "Uncapped micro-batching for 24GB+ VRAM workstation GPUs" },
151
+ ];
152
+ const currentBudget = config.gpuAttentionBudget || 2000000;
153
+ const initialIdx = Math.max(0, budgetItems.findIndex((i) => i.value === currentBudget));
154
+ const subRes = await selectSimpleMenu({
155
+ title: "SELECT GPU MICRO-BATCH ATTENTION BUDGET",
156
+ subtitle: "Controls dynamic O(seq_len^2) sub-batching to prevent VRAM overflow",
157
+ items: budgetItems,
158
+ initialIndex: initialIdx,
159
+ });
160
+ if (subRes.action === "select") {
161
+ updateConfig({ gpuAttentionBudget: subRes.value });
162
+ }
163
+ break;
164
+ }
165
+ case "onnx_threads": {
166
+ const threadItems = [
167
+ { label: "0 - Auto (Detect CPU Cores)", value: 0, info: "Automatically match physical CPU cores (up to 8)" },
168
+ { label: "1 Thread (Single-Threaded)", value: 1, info: "Restrict ONNX WASM to 1 thread" },
169
+ { label: "2 Threads", value: 2, info: "Use 2 WASM threads" },
170
+ { label: "4 Threads", value: 4, info: "Use 4 WASM threads" },
171
+ { label: "8 Threads", value: 8, info: "Use 8 WASM threads" },
172
+ { label: "16 Threads", value: 16, info: "Use 16 WASM threads" },
173
+ ];
174
+ const currentThreads = config.onnxThreads || 0;
175
+ const initialThreadIdx = Math.max(0, threadItems.findIndex((i) => i.value === currentThreads));
176
+ const subRes = await selectSimpleMenu({
177
+ title: "SELECT CPU ONNX WASM THREADS",
178
+ subtitle: "Number of WASM worker threads for ONNX Runtime",
179
+ items: threadItems,
180
+ initialIndex: initialThreadIdx,
181
+ });
182
+ if (subRes.action === "select") {
183
+ updateConfig({ onnxThreads: subRes.value });
184
+ }
185
+ break;
186
+ }
187
+ case "execution_device": {
188
+ const devItems = [
189
+ {
190
+ label: "CPU (AVX2 / WASM SIMD - RECOMMENDED)",
191
+ value: "cpu",
192
+ info: "Standard multi-threaded CPU execution via ONNX native AVX2 (Optimal speed, stability & zero VRAM overhead)",
193
+ },
194
+ {
195
+ label: "\x1b[31m[EXPERIMENTAL]\x1b[0m GPU (DirectML / WebGPU)",
196
+ value: "webgpu",
197
+ info: "⚠️ EXPERIMENTAL: DirectML GPU tensor execution. High JS FFI & zero-padding overhead; CPU AVX2 is recommended for local Node.js.",
198
+ },
199
+ ];
200
+ const currentDev = config.executionDevice || "cpu";
201
+ const initialDevIdx = Math.max(0, devItems.findIndex((i) => i.value === currentDev));
202
+ const subRes = await selectSimpleMenu({
203
+ title: "SELECT EXECUTION HARDWARE DEVICE",
204
+ subtitle: "CPU AVX2 (Recommended) vs Experimental DirectML GPU Hardware Mode",
205
+ items: devItems,
206
+ initialIndex: initialDevIdx,
207
+ });
208
+ if (subRes.action === "select") {
209
+ updateConfig({ executionDevice: subRes.value });
210
+ }
211
+ break;
212
+ }
213
+ }
214
+ }
@@ -0,0 +1,24 @@
1
+ import { waitForEnter } from "../ui.js";
2
+
3
+ export async function handlePromptAction(value) {
4
+ switch (value) {
5
+ case "enable_prompt": {
6
+ const { enableGlobalPrompt } = await import("../../prompt_manager.js");
7
+ const results = await enableGlobalPrompt();
8
+ console.clear();
9
+ console.log("\n [OK] Global prompt enabled across client configurations:\n");
10
+ results.forEach((r) => console.log(` - ${r.name}: ${r.filePath} (${r.status})`));
11
+ await waitForEnter();
12
+ break;
13
+ }
14
+ case "disable_prompt": {
15
+ const { disableGlobalPrompt } = await import("../../prompt_manager.js");
16
+ const results = await disableGlobalPrompt();
17
+ console.clear();
18
+ console.log("\n [OK] Global prompt disabled across client configurations:\n");
19
+ results.forEach((r) => console.log(` - ${r.name}: ${r.filePath} (${r.status})`));
20
+ await waitForEnter();
21
+ break;
22
+ }
23
+ }
24
+ }