forked from ob-labs/memory-powermem
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconfig.ts
More file actions
194 lines (174 loc) · 5.8 KB
/
config.ts
File metadata and controls
194 lines (174 loc) · 5.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/**
* PowerMem memory plugin configuration.
* Validates baseUrl, optional apiKey, and user/agent mapping.
*/
import { homedir } from "node:os";
import { join } from "node:path";
function assertAllowedKeys(
value: Record<string, unknown>,
allowed: string[],
label: string,
) {
const unknown = Object.keys(value).filter((key) => !allowed.includes(key));
if (unknown.length === 0) return;
throw new Error(`${label} has unknown keys: ${unknown.join(", ")}`);
}
function resolveEnvVars(value: string): string {
return value.replace(/\$\{([^}]+)\}/g, (_, envVar) => {
const envValue = process.env[envVar];
if (!envValue) {
throw new Error(`Environment variable ${envVar} is not set`);
}
return envValue;
});
}
export type PowerMemMode = "http" | "cli";
export type PowerMemConfig = {
mode: PowerMemMode;
baseUrl: string;
apiKey?: string;
/** CLI mode: path to .env (optional; pmem discovers if omitted). */
envFile?: string;
/** CLI mode: path to pmem binary (default "pmem"). */
pmemPath?: string;
/**
* When true (default), inject LLM/embedding from OpenClaw gateway config into `pmem`
* (overrides the same keys from an optional .env file). SQLite defaults live under the OpenClaw state dir.
*/
useOpenClawModel?: boolean;
userId?: string;
agentId?: string;
/** Max memories to return in recall / inject in auto-recall. Default 5. */
recallLimit?: number;
/** Min score (0–1) for recall; memories below are filtered. Default 0. */
recallScoreThreshold?: number;
autoCapture: boolean;
autoRecall: boolean;
inferOnAdd: boolean;
};
const DEFAULT_RECALL_LIMIT = 5;
const DEFAULT_RECALL_SCORE_THRESHOLD = 0;
const ALLOWED_KEYS = [
"mode",
"baseUrl",
"apiKey",
"envFile",
"pmemPath",
"useOpenClawModel",
"userId",
"agentId",
"recallLimit",
"recallScoreThreshold",
"autoCapture",
"autoRecall",
"inferOnAdd",
] as const;
export const powerMemConfigSchema = {
parse(value: unknown): PowerMemConfig {
if (!value || typeof value !== "object" || Array.isArray(value)) {
throw new Error("memory-powermem config required");
}
const cfg = value as Record<string, unknown>;
assertAllowedKeys(cfg, [...ALLOWED_KEYS], "memory-powermem config");
const modeExplicit =
cfg.mode === "cli" || cfg.mode === "http" ? cfg.mode : undefined;
const baseUrlForInfer =
typeof cfg.baseUrl === "string" ? cfg.baseUrl.trim() : "";
const mode =
modeExplicit ?? (baseUrlForInfer ? "http" : "cli");
let baseUrl = "";
let apiKey: string | undefined;
if (mode === "http") {
const baseUrlRaw = cfg.baseUrl;
if (typeof baseUrlRaw !== "string" || !baseUrlRaw.trim()) {
throw new Error("memory-powermem baseUrl is required when mode is http");
}
baseUrl = resolveEnvVars(baseUrlRaw.trim()).replace(/\/+$/, "");
const apiKeyRaw = cfg.apiKey;
apiKey =
typeof apiKeyRaw === "string" && apiKeyRaw.trim()
? resolveEnvVars(apiKeyRaw.trim())
: undefined;
}
const envFileRaw = cfg.envFile;
const envFile =
typeof envFileRaw === "string" && envFileRaw.trim()
? envFileRaw.trim()
: undefined;
const pmemPathRaw = cfg.pmemPath;
const pmemPath =
typeof pmemPathRaw === "string" && pmemPathRaw.trim()
? pmemPathRaw.trim()
: "pmem";
return {
mode,
baseUrl,
apiKey,
envFile,
pmemPath,
useOpenClawModel: cfg.useOpenClawModel !== false,
userId:
typeof cfg.userId === "string" && cfg.userId.trim()
? cfg.userId.trim()
: undefined,
agentId:
typeof cfg.agentId === "string" && cfg.agentId.trim()
? cfg.agentId.trim()
: undefined,
recallLimit: toRecallLimit(cfg.recallLimit),
recallScoreThreshold: toRecallScoreThreshold(cfg.recallScoreThreshold),
autoCapture: cfg.autoCapture !== false,
autoRecall: cfg.autoRecall !== false,
inferOnAdd: cfg.inferOnAdd !== false,
};
},
};
function toRecallLimit(v: unknown): number {
if (typeof v === "number" && Number.isFinite(v) && v >= 1) {
return Math.min(100, Math.floor(v));
}
if (typeof v === "string" && /^\d+$/.test(v)) {
const n = parseInt(v, 10);
return n >= 1 ? Math.min(100, n) : DEFAULT_RECALL_LIMIT;
}
return DEFAULT_RECALL_LIMIT;
}
function toRecallScoreThreshold(v: unknown): number {
if (typeof v === "number" && Number.isFinite(v)) {
return Math.max(0, Math.min(1, v));
}
if (typeof v === "string" && v.trim() !== "") {
const n = Number(v);
if (Number.isFinite(n)) return Math.max(0, Math.min(1, n));
}
return DEFAULT_RECALL_SCORE_THRESHOLD;
}
/** Default user/agent IDs when not configured (single-tenant style). */
export const DEFAULT_USER_ID = "openclaw-user";
export const DEFAULT_AGENT_ID = "openclaw-agent";
/** Canonical PowerMem `.env` path for consumer (CLI) setups; matches install.sh. */
export function defaultConsumerPowermemEnvPath(): string {
return join(homedir(), ".openclaw", "powermem", "powermem.env");
}
/**
* Default plugin config when openclaw.json has no plugins.entries["memory-powermem"].config.
* Consumer default: CLI, no .env required — SQLite under OpenClaw state dir + LLM from OpenClaw `agents.defaults.model`.
* Optional: set `envFile` to merge a powermem .env under OpenClaw-derived vars.
* Enterprise / shared server: set `mode: "http"` and `baseUrl`.
*/
export const DEFAULT_PLUGIN_CONFIG: PowerMemConfig = {
mode: "cli",
baseUrl: "",
envFile: undefined,
pmemPath: "pmem",
useOpenClawModel: true,
autoCapture: true,
autoRecall: true,
inferOnAdd: true,
};
export function resolveUserId(cfg: PowerMemConfig): string {
return cfg.userId ?? DEFAULT_USER_ID;
}
export function resolveAgentId(cfg: PowerMemConfig): string {
return cfg.agentId ?? DEFAULT_AGENT_ID;
}