openclaw-memory-decay 0.1.4 → 0.1.6
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/README.md +75 -30
- package/openclaw.plugin.json +36 -3
- package/package.json +4 -1
- package/scripts/detect-python-lib.mjs +85 -0
- package/scripts/detect-python.mjs +9 -25
- package/src/index.ts +8 -4
- package/src/python-env.ts +14 -0
package/README.md
CHANGED
|
@@ -51,16 +51,20 @@ Activation
|
|
|
51
51
|
- **Proactive agent saves** — the agent stores preferences, decisions, facts, and episodes without being asked
|
|
52
52
|
- **Freshness indicators** — search results include `fresh` / `normal` / `stale` so the agent can judge reliability
|
|
53
53
|
- **Dual-score model** — storage score (can it be found?) and retrieval score (how easily?) are tracked separately
|
|
54
|
-
-
|
|
54
|
+
- **Memory tools** — the plugin exposes `memory_search`, `memory_store`, and `memory_store_batch`
|
|
55
55
|
- **Markdown migration** — imports existing `~/.openclaw/workspace/memory/` files on first run
|
|
56
56
|
|
|
57
57
|
## Quick Start
|
|
58
58
|
|
|
59
|
+
> Deprecated: installing from a cloned checkout via `openclaw plugins install -l .` is no longer the recommended path. Use the published npm package instead.
|
|
60
|
+
|
|
59
61
|
```bash
|
|
60
|
-
# 1. Install
|
|
61
|
-
|
|
62
|
+
# 1. Install the backend into a dedicated virtualenv
|
|
63
|
+
python3 -m venv ~/.openclaw/venvs/memory-decay
|
|
64
|
+
~/.openclaw/venvs/memory-decay/bin/pip install memory-decay
|
|
62
65
|
|
|
63
|
-
# 2. Install this plugin
|
|
66
|
+
# 2. Install this plugin while that venv is active
|
|
67
|
+
source ~/.openclaw/venvs/memory-decay/bin/activate
|
|
64
68
|
openclaw plugins install openclaw-memory-decay
|
|
65
69
|
|
|
66
70
|
# 3. (Optional but recommended) Restrict auto-load to trusted plugins only
|
|
@@ -70,13 +74,44 @@ openclaw config set plugins.allow '["memory-decay"]'
|
|
|
70
74
|
openclaw gateway restart
|
|
71
75
|
```
|
|
72
76
|
|
|
73
|
-
> **Note:**
|
|
77
|
+
> **Note:** If the plugin is already loaded, install may succeed silently. Use `openclaw plugins list` to confirm status is `loaded`.
|
|
74
78
|
|
|
75
79
|
### Prerequisites
|
|
76
80
|
|
|
77
81
|
- [OpenClaw](https://openclaw.ai) installed globally
|
|
78
82
|
- Python 3.10+
|
|
79
|
-
-
|
|
83
|
+
- A Python virtualenv containing `memory-decay`
|
|
84
|
+
|
|
85
|
+
## Migration From Deprecated Local Install
|
|
86
|
+
|
|
87
|
+
If you previously installed this plugin from a local checkout via `openclaw plugins install -l .`, migrate to the npm package. Local/path-based installs are now deprecated in favor of the published npm package.
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
# 1. Install from npm instead
|
|
91
|
+
openclaw plugins install openclaw-memory-decay
|
|
92
|
+
|
|
93
|
+
# 2. Restart gateway
|
|
94
|
+
openclaw gateway restart
|
|
95
|
+
|
|
96
|
+
# 3. Verify
|
|
97
|
+
openclaw plugins list | grep memory-decay # should show: memory-decay | loaded
|
|
98
|
+
curl -s http://127.0.0.1:8100/health # should show: {"status":"ok","current_tick":0}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
If auto-detection does not recover your backend path after migration, set the interpreter explicitly:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
openclaw config set plugins.entries.memory-decay.config.pythonPath "~/.openclaw/venvs/memory-decay/bin/python"
|
|
105
|
+
openclaw gateway restart
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Your memories are safe.** The SQLite database (`memories.db`) is not affected by plugin reinstallation or migration to npm install.
|
|
109
|
+
|
|
110
|
+
To update in the future:
|
|
111
|
+
```bash
|
|
112
|
+
openclaw plugins update memory-decay
|
|
113
|
+
openclaw gateway restart
|
|
114
|
+
```
|
|
80
115
|
|
|
81
116
|
## Configuration
|
|
82
117
|
|
|
@@ -102,8 +137,8 @@ Add to `~/.openclaw/openclaw.json` under `plugins.entries.memory-decay.config`:
|
|
|
102
137
|
| Option | Default | Description |
|
|
103
138
|
|--------|---------|-------------|
|
|
104
139
|
| `serverPort` | `8100` | Port for the memory-decay HTTP server |
|
|
105
|
-
| `memoryDecayPath` | (auto) | Path to memory-decay-core. Auto-detected from
|
|
106
|
-
| `pythonPath` | `python3` | Path to Python interpreter
|
|
140
|
+
| `memoryDecayPath` | (auto) | Path to memory-decay-core. Auto-detected from the install-time Python environment if not set |
|
|
141
|
+
| `pythonPath` | `python3` | Path to Python interpreter. Set this explicitly if the gateway runs outside the install-time venv |
|
|
107
142
|
| `dbPath` | `~/.openclaw/memory-decay-data/memories.db` | SQLite database location |
|
|
108
143
|
| `autoSave` | `true` | Auto-save every conversation turn at low importance. Set `false` to let the agent decide what to save |
|
|
109
144
|
| `embeddingProvider` | `local` | Embedding provider: `local`, `openai`, or `gemini` |
|
|
@@ -149,7 +184,7 @@ The bootstrap prompt and skills guide the agent to pick the right category and i
|
|
|
149
184
|
| `fact` | Technical facts, API behaviors, architecture | 0.7–0.9 | "Auth service returns inconsistent 4xx on token expiry" |
|
|
150
185
|
| `episode` | What was worked on, session context | 0.3–0.6 | "Finished migrating auth middleware" |
|
|
151
186
|
|
|
152
|
-
The agent stores proactively based on conversation triggers — it doesn't wait
|
|
187
|
+
The agent stores proactively based on conversation triggers — it doesn't wait to be explicitly asked.
|
|
153
188
|
|
|
154
189
|
## How It Works
|
|
155
190
|
|
|
@@ -192,17 +227,15 @@ The plugin manages the Python server lifecycle — starts with the gateway, stop
|
|
|
192
227
|
4. **Reinforce** — recalled memories get boosted (testing effect), stability grows
|
|
193
228
|
5. **Forget** — memories with very low activation become practically unretrievable
|
|
194
229
|
|
|
195
|
-
##
|
|
230
|
+
## Tools
|
|
196
231
|
|
|
197
|
-
The plugin registers these
|
|
232
|
+
The plugin registers these tools:
|
|
198
233
|
|
|
199
|
-
|
|
|
200
|
-
|
|
201
|
-
|
|
|
202
|
-
|
|
|
203
|
-
|
|
|
204
|
-
| `/memory-status` | `/memory-status` | Show memory count, tick, and decay stats |
|
|
205
|
-
| `/migrate` | `/migrate` | Import Markdown files from `memory/` directory |
|
|
234
|
+
| Tool | Purpose |
|
|
235
|
+
|------|---------|
|
|
236
|
+
| `memory_search` | Search memories with decay-aware ranking and freshness indicators |
|
|
237
|
+
| `memory_store` | Save a single memory with calibrated importance and category |
|
|
238
|
+
| `memory_store_batch` | Save multiple memories efficiently in one call |
|
|
206
239
|
|
|
207
240
|
## Troubleshooting
|
|
208
241
|
|
|
@@ -224,16 +257,26 @@ openclaw plugins install openclaw-memory-decay
|
|
|
224
257
|
### `Memory service not running`
|
|
225
258
|
|
|
226
259
|
```bash
|
|
227
|
-
# Check if
|
|
228
|
-
|
|
260
|
+
# Check if the configured Python can import the server
|
|
261
|
+
~/.openclaw/venvs/memory-decay/bin/python -c "import memory_decay.server; print('ok')"
|
|
229
262
|
|
|
230
263
|
# Check server health
|
|
231
264
|
curl http://127.0.0.1:8100/health
|
|
232
265
|
```
|
|
233
266
|
|
|
234
|
-
If
|
|
267
|
+
If the import check fails, install the backend into a virtualenv and either reactivate that venv before reinstalling the plugin or set `pythonPath` explicitly:
|
|
268
|
+
```bash
|
|
269
|
+
python3 -m venv ~/.openclaw/venvs/memory-decay
|
|
270
|
+
~/.openclaw/venvs/memory-decay/bin/pip install memory-decay
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
### `error: externally-managed-environment`
|
|
274
|
+
|
|
275
|
+
Your system Python is PEP 668 managed. Install `memory-decay` into a virtualenv instead of the system interpreter:
|
|
276
|
+
|
|
235
277
|
```bash
|
|
236
|
-
|
|
278
|
+
python3 -m venv ~/.openclaw/venvs/memory-decay
|
|
279
|
+
~/.openclaw/venvs/memory-decay/bin/pip install memory-decay
|
|
237
280
|
```
|
|
238
281
|
|
|
239
282
|
### Plugin shows `error` status
|
|
@@ -245,15 +288,17 @@ openclaw plugins doctor
|
|
|
245
288
|
## For AI Agents: Self-Installation Guide
|
|
246
289
|
|
|
247
290
|
> This section is written for LLM agents to follow autonomously. If you're a human, use the [Quick Start](#quick-start) section above.
|
|
291
|
+
> Use the published npm package. Do not install this plugin from a cloned checkout unless you are actively developing it.
|
|
248
292
|
|
|
249
293
|
### Quick Install (one-shot)
|
|
250
294
|
|
|
251
295
|
```bash
|
|
252
|
-
# 1. Install the backend
|
|
253
|
-
|
|
296
|
+
# 1. Install the backend into a dedicated virtualenv
|
|
297
|
+
python3 -m venv ~/.openclaw/venvs/memory-decay
|
|
298
|
+
~/.openclaw/venvs/memory-decay/bin/pip install memory-decay
|
|
254
299
|
|
|
255
|
-
# 2.
|
|
256
|
-
|
|
300
|
+
# 2. Activate the venv so postinstall detects the same interpreter
|
|
301
|
+
source ~/.openclaw/venvs/memory-decay/bin/activate
|
|
257
302
|
|
|
258
303
|
# 3. Install plugin from npm
|
|
259
304
|
openclaw plugins install openclaw-memory-decay
|
|
@@ -285,14 +330,14 @@ openclaw plugins install openclaw-memory-decay
|
|
|
285
330
|
|
|
286
331
|
**`Memory service not running`:**
|
|
287
332
|
```bash
|
|
288
|
-
# Check backend
|
|
289
|
-
|
|
333
|
+
# Check the configured Python can import the backend server
|
|
334
|
+
~/.openclaw/venvs/memory-decay/bin/python -c "import memory_decay.server; print('ok')"
|
|
290
335
|
|
|
291
336
|
# Check if gateway started it
|
|
292
337
|
curl -s http://127.0.0.1:8100/health
|
|
293
338
|
|
|
294
|
-
# If
|
|
295
|
-
pip install memory-decay
|
|
339
|
+
# If the import fails, reinstall into the venv:
|
|
340
|
+
~/.openclaw/venvs/memory-decay/bin/pip install memory-decay
|
|
296
341
|
openclaw gateway restart
|
|
297
342
|
```
|
|
298
343
|
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,10 +2,43 @@
|
|
|
2
2
|
"id": "memory-decay",
|
|
3
3
|
"name": "Memory Decay",
|
|
4
4
|
"description": "Human-like memory with decay and reinforcement for OpenClaw agents",
|
|
5
|
-
"version": "0.1.
|
|
5
|
+
"version": "0.1.6",
|
|
6
6
|
"configSchema": {
|
|
7
7
|
"type": "object",
|
|
8
|
-
"additionalProperties":
|
|
9
|
-
"properties": {
|
|
8
|
+
"additionalProperties": true,
|
|
9
|
+
"properties": {
|
|
10
|
+
"serverPort": {
|
|
11
|
+
"type": "number",
|
|
12
|
+
"default": 8100
|
|
13
|
+
},
|
|
14
|
+
"pythonPath": {
|
|
15
|
+
"type": "string"
|
|
16
|
+
},
|
|
17
|
+
"memoryDecayPath": {
|
|
18
|
+
"type": "string"
|
|
19
|
+
},
|
|
20
|
+
"dbPath": {
|
|
21
|
+
"type": "string"
|
|
22
|
+
},
|
|
23
|
+
"autoSave": {
|
|
24
|
+
"type": "boolean",
|
|
25
|
+
"default": true
|
|
26
|
+
},
|
|
27
|
+
"embeddingProvider": {
|
|
28
|
+
"type": "string"
|
|
29
|
+
},
|
|
30
|
+
"embeddingApiKey": {
|
|
31
|
+
"type": "string"
|
|
32
|
+
},
|
|
33
|
+
"embeddingModel": {
|
|
34
|
+
"type": "string"
|
|
35
|
+
},
|
|
36
|
+
"embeddingDim": {
|
|
37
|
+
"type": "number"
|
|
38
|
+
},
|
|
39
|
+
"experimentDir": {
|
|
40
|
+
"type": "string"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
10
43
|
}
|
|
11
44
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openclaw-memory-decay",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenClaw memory plugin backed by memory-decay engine",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -41,5 +41,8 @@
|
|
|
41
41
|
"repository": {
|
|
42
42
|
"type": "git",
|
|
43
43
|
"url": "https://github.com/memory-decay/openclaw-memory-decay"
|
|
44
|
+
},
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
44
47
|
}
|
|
45
48
|
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { execFileSync as nodeExecFileSync } from "node:child_process";
|
|
2
|
+
import { existsSync as nodeExistsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { basename, dirname, isAbsolute, join, resolve } from "node:path";
|
|
5
|
+
|
|
6
|
+
function resolvePythonPath(command, { execFileSync = nodeExecFileSync, isWin = process.platform === "win32" } = {}) {
|
|
7
|
+
if (isAbsolute(command)) {
|
|
8
|
+
return command;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const resolver = isWin ? "where" : "which";
|
|
12
|
+
return execFileSync(resolver, [command], { encoding: "utf8" }).trim().split(/\r?\n/)[0];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function resolveMemoryDecayPath(moduleFile) {
|
|
16
|
+
const packageDir = dirname(resolve(moduleFile));
|
|
17
|
+
const packageParent = dirname(packageDir);
|
|
18
|
+
return basename(packageParent) === "src" ? dirname(packageParent) : packageParent;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function buildPythonCandidates({
|
|
22
|
+
pluginRoot,
|
|
23
|
+
env = process.env,
|
|
24
|
+
isWin = process.platform === "win32",
|
|
25
|
+
existsSync = nodeExistsSync,
|
|
26
|
+
} = {}) {
|
|
27
|
+
const siblingRoots = [
|
|
28
|
+
resolve(pluginRoot, "../memory-decay"),
|
|
29
|
+
resolve(pluginRoot, "../memory-decay-core"),
|
|
30
|
+
];
|
|
31
|
+
const pathCandidates = [];
|
|
32
|
+
|
|
33
|
+
if (env.MD_PYTHON_PATH) pathCandidates.push(env.MD_PYTHON_PATH);
|
|
34
|
+
if (env.VIRTUAL_ENV) {
|
|
35
|
+
pathCandidates.push(join(env.VIRTUAL_ENV, isWin ? "Scripts/python.exe" : "bin/python"));
|
|
36
|
+
}
|
|
37
|
+
for (const root of siblingRoots) {
|
|
38
|
+
pathCandidates.push(join(root, isWin ? ".venv/Scripts/python.exe" : ".venv/bin/python"));
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const commandCandidates = isWin ? ["python"] : ["python3", "python"];
|
|
42
|
+
return [...new Set([
|
|
43
|
+
...pathCandidates.filter((candidate) => existsSync(candidate)),
|
|
44
|
+
...commandCandidates,
|
|
45
|
+
])];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function detectPythonEnv({
|
|
49
|
+
pluginRoot,
|
|
50
|
+
env = process.env,
|
|
51
|
+
isWin = process.platform === "win32",
|
|
52
|
+
existsSync = nodeExistsSync,
|
|
53
|
+
execFileSync = nodeExecFileSync,
|
|
54
|
+
makeTempDir = () => mkdtempSync(join(tmpdir(), "memory-decay-python-env-")),
|
|
55
|
+
readPathFile = (path) => readFileSync(path, "utf8"),
|
|
56
|
+
removeTempDir = (path) => rmSync(path, { recursive: true, force: true }),
|
|
57
|
+
} = {}) {
|
|
58
|
+
for (const candidate of buildPythonCandidates({ pluginRoot, env, isWin, existsSync })) {
|
|
59
|
+
try {
|
|
60
|
+
execFileSync(candidate, ["-c", "import memory_decay.server"], { stdio: "ignore" });
|
|
61
|
+
const tempDir = makeTempDir();
|
|
62
|
+
const outputPath = join(tempDir, "memory-decay-module-path.txt");
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
execFileSync(candidate, [
|
|
66
|
+
"-c",
|
|
67
|
+
`import memory_decay, pathlib; pathlib.Path(${JSON.stringify(outputPath)}).write_text(str(pathlib.Path(memory_decay.__file__).resolve()))`,
|
|
68
|
+
], { stdio: "ignore" });
|
|
69
|
+
} catch (error) {
|
|
70
|
+
removeTempDir(tempDir);
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const moduleFile = readPathFile(outputPath).trim();
|
|
75
|
+
removeTempDir(tempDir);
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
pythonPath: resolvePythonPath(candidate, { execFileSync, isWin }),
|
|
79
|
+
memoryDecayPath: resolveMemoryDecayPath(moduleFile),
|
|
80
|
+
};
|
|
81
|
+
} catch {}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
@@ -1,35 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { execSync } from "node:child_process";
|
|
3
2
|
import { writeFileSync } from "node:fs";
|
|
4
3
|
import { resolve, dirname } from "node:path";
|
|
5
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { detectPythonEnv } from "./detect-python-lib.mjs";
|
|
6
6
|
|
|
7
7
|
const root = dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
const
|
|
9
|
-
const candidates = isWin ? ["python"] : ["python3", "python"];
|
|
8
|
+
const detected = detectPythonEnv({ pluginRoot: resolve(root, "..") });
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
);
|
|
17
|
-
return true;
|
|
18
|
-
} catch {
|
|
19
|
-
return false;
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
if (!python) {
|
|
24
|
-
console.warn("[memory-decay] memory_decay not found — run: pip install memory-decay");
|
|
10
|
+
if (!detected) {
|
|
11
|
+
console.warn(
|
|
12
|
+
"[memory-decay] memory_decay server not found in an active or sibling Python environment. " +
|
|
13
|
+
"Install the backend in a venv and rerun install, or set pythonPath in plugin config.",
|
|
14
|
+
);
|
|
25
15
|
process.exit(0);
|
|
26
16
|
}
|
|
27
17
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
`${python} -c "import memory_decay,os; print(os.path.dirname(os.path.dirname(memory_decay.__file__)))"`,
|
|
31
|
-
{ encoding: "utf8" }
|
|
32
|
-
).trim();
|
|
33
|
-
|
|
34
|
-
writeFileSync(resolve(root, "../.python-env.json"), JSON.stringify({ pythonPath, memoryDecayPath }, null, 2));
|
|
35
|
-
console.log(`[memory-decay] Detected: ${pythonPath}`);
|
|
18
|
+
writeFileSync(resolve(root, "../.python-env.json"), JSON.stringify(detected, null, 2));
|
|
19
|
+
console.log(`[memory-decay] Detected: ${detected.pythonPath}`);
|
package/src/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { emptyPluginConfigSchema } from "openclaw/plugin-sdk";
|
|
|
3
3
|
import { MemoryDecayClient } from "./client.js";
|
|
4
4
|
import { MemoryDecayService, type ServiceConfig } from "./service.js";
|
|
5
5
|
import { shouldMigrate, migrateMarkdownMemories } from "./migrator.js";
|
|
6
|
+
import { mergePythonEnv } from "./python-env.js";
|
|
6
7
|
import { toFreshness } from "./types.js";
|
|
7
8
|
|
|
8
9
|
const BOOTSTRAP_PROMPT = `## Memory System (memory-decay)
|
|
@@ -88,17 +89,20 @@ const memoryDecayPlugin = {
|
|
|
88
89
|
// Resolve pythonPath + memoryDecayPath: config > .python-env.json (set at install time) > error
|
|
89
90
|
let memoryDecayPath = (cfg.memoryDecayPath as string) ?? "";
|
|
90
91
|
let pythonPath = (cfg.pythonPath as string) ?? "";
|
|
91
|
-
|
|
92
|
+
let detectedEnv: { memoryDecayPath?: string; pythonPath?: string } = {};
|
|
93
|
+
if (!memoryDecayPath || !pythonPath) {
|
|
92
94
|
try {
|
|
93
95
|
const { readFileSync } = await import("node:fs");
|
|
94
96
|
const { resolve, dirname } = await import("node:path");
|
|
95
97
|
const { fileURLToPath } = await import("node:url");
|
|
96
98
|
const pluginRoot = dirname(fileURLToPath(import.meta.url));
|
|
97
|
-
|
|
98
|
-
if (!pythonPath && detected.pythonPath) pythonPath = detected.pythonPath;
|
|
99
|
-
if (detected.memoryDecayPath) memoryDecayPath = detected.memoryDecayPath;
|
|
99
|
+
detectedEnv = JSON.parse(readFileSync(resolve(pluginRoot, "../.python-env.json"), "utf8"));
|
|
100
100
|
} catch {}
|
|
101
101
|
}
|
|
102
|
+
({ memoryDecayPath, pythonPath } = mergePythonEnv(
|
|
103
|
+
{ memoryDecayPath, pythonPath },
|
|
104
|
+
detectedEnv,
|
|
105
|
+
));
|
|
102
106
|
if (!memoryDecayPath) {
|
|
103
107
|
ctx.logger.error(
|
|
104
108
|
"Could not auto-detect memory-decay installation. " +
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface PythonEnvLike {
|
|
2
|
+
memoryDecayPath?: string;
|
|
3
|
+
pythonPath?: string;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export function mergePythonEnv(
|
|
7
|
+
configured: PythonEnvLike,
|
|
8
|
+
detected: PythonEnvLike = {},
|
|
9
|
+
): { memoryDecayPath: string; pythonPath: string } {
|
|
10
|
+
return {
|
|
11
|
+
memoryDecayPath: configured.memoryDecayPath || detected.memoryDecayPath || "",
|
|
12
|
+
pythonPath: configured.pythonPath || detected.pythonPath || "",
|
|
13
|
+
};
|
|
14
|
+
}
|