@agentmemory/agentmemory 0.7.9 → 0.8.1
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 +131 -112
- package/dist/cli.mjs +57 -13
- package/dist/cli.mjs.map +1 -1
- package/dist/index.mjs +149 -17
- package/dist/index.mjs.map +1 -1
- package/dist/{src-DNbB7fd7.mjs → src-Df36IFVL.mjs} +150 -18
- package/dist/src-Df36IFVL.mjs.map +1 -0
- package/dist/standalone.mjs +1 -1
- package/dist/standalone.mjs.map +1 -1
- package/dist/viewer/index.html +2888 -0
- package/package.json +2 -2
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/src-DNbB7fd7.mjs.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -40,10 +40,16 @@ function loadEnvFile() {
|
|
|
40
40
|
}
|
|
41
41
|
function detectProvider(env) {
|
|
42
42
|
const maxTokens = parseInt(env["MAX_TOKENS"] || "4096", 10);
|
|
43
|
+
if (env["MINIMAX_API_KEY"]) return {
|
|
44
|
+
provider: "minimax",
|
|
45
|
+
model: env["MINIMAX_MODEL"] || "MiniMax-M2.7",
|
|
46
|
+
maxTokens
|
|
47
|
+
};
|
|
43
48
|
if (env["ANTHROPIC_API_KEY"]) return {
|
|
44
49
|
provider: "anthropic",
|
|
45
50
|
model: env["ANTHROPIC_MODEL"] || "claude-sonnet-4-20250514",
|
|
46
|
-
maxTokens
|
|
51
|
+
maxTokens,
|
|
52
|
+
baseURL: env["ANTHROPIC_BASE_URL"]
|
|
47
53
|
};
|
|
48
54
|
if (env["GEMINI_API_KEY"]) return {
|
|
49
55
|
provider: "gemini",
|
|
@@ -157,7 +163,8 @@ const VALID_PROVIDERS = new Set([
|
|
|
157
163
|
"anthropic",
|
|
158
164
|
"gemini",
|
|
159
165
|
"openrouter",
|
|
160
|
-
"agent-sdk"
|
|
166
|
+
"agent-sdk",
|
|
167
|
+
"minimax"
|
|
161
168
|
]);
|
|
162
169
|
function loadFallbackConfig() {
|
|
163
170
|
return { providers: (getMergedEnv()["FALLBACK_PROVIDERS"] || "").split(",").map((p) => p.trim()).filter((p) => Boolean(p) && VALID_PROVIDERS.has(p)) };
|
|
@@ -196,8 +203,11 @@ var AnthropicProvider = class {
|
|
|
196
203
|
client;
|
|
197
204
|
model;
|
|
198
205
|
maxTokens;
|
|
199
|
-
constructor(apiKey, model, maxTokens) {
|
|
200
|
-
this.client = new Anthropic({
|
|
206
|
+
constructor(apiKey, model, maxTokens, baseURL) {
|
|
207
|
+
this.client = new Anthropic({
|
|
208
|
+
apiKey,
|
|
209
|
+
...baseURL ? { baseURL } : {}
|
|
210
|
+
});
|
|
201
211
|
this.model = model;
|
|
202
212
|
this.maxTokens = maxTokens;
|
|
203
213
|
}
|
|
@@ -220,6 +230,67 @@ var AnthropicProvider = class {
|
|
|
220
230
|
}
|
|
221
231
|
};
|
|
222
232
|
|
|
233
|
+
//#endregion
|
|
234
|
+
//#region src/providers/minimax.ts
|
|
235
|
+
/**
|
|
236
|
+
* MiniMax provider using raw fetch to call MiniMax's Anthropic-compatible API.
|
|
237
|
+
*
|
|
238
|
+
* The Anthropic SDK automatically injects `x-stainless-*` headers that MiniMax
|
|
239
|
+
* rejects with 403. This provider bypasses the SDK and calls the API directly.
|
|
240
|
+
*
|
|
241
|
+
* Required env vars:
|
|
242
|
+
* MINIMAX_API_KEY — your MiniMax API key
|
|
243
|
+
* MINIMAX_MODEL — model name (default: MiniMax-M2.7)
|
|
244
|
+
* MAX_TOKENS — max output tokens (default: 800; MiniMax-M2.7 needs ≤800)
|
|
245
|
+
*
|
|
246
|
+
* Optional:
|
|
247
|
+
* MINIMAX_BASE_URL — base URL without path (default: https://api.minimaxi.com/anthropic)
|
|
248
|
+
*/
|
|
249
|
+
var MinimaxProvider = class {
|
|
250
|
+
name = "minimax";
|
|
251
|
+
apiKey;
|
|
252
|
+
model;
|
|
253
|
+
maxTokens;
|
|
254
|
+
baseUrl;
|
|
255
|
+
constructor(apiKey, model, maxTokens) {
|
|
256
|
+
this.apiKey = apiKey;
|
|
257
|
+
this.model = model;
|
|
258
|
+
this.maxTokens = maxTokens;
|
|
259
|
+
this.baseUrl = process.env["MINIMAX_BASE_URL"] || "https://api.minimaxi.com/anthropic";
|
|
260
|
+
}
|
|
261
|
+
async compress(systemPrompt, userPrompt) {
|
|
262
|
+
return this.call(systemPrompt, userPrompt);
|
|
263
|
+
}
|
|
264
|
+
async summarize(systemPrompt, userPrompt) {
|
|
265
|
+
return this.call(systemPrompt, userPrompt);
|
|
266
|
+
}
|
|
267
|
+
async call(systemPrompt, userPrompt) {
|
|
268
|
+
const url = `${this.baseUrl}/v1/messages`;
|
|
269
|
+
const response = await fetch(url, {
|
|
270
|
+
method: "POST",
|
|
271
|
+
headers: {
|
|
272
|
+
"Content-Type": "application/json",
|
|
273
|
+
"x-api-key": this.apiKey,
|
|
274
|
+
"anthropic-version": "2023-06-01"
|
|
275
|
+
},
|
|
276
|
+
body: JSON.stringify({
|
|
277
|
+
model: this.model,
|
|
278
|
+
max_tokens: this.maxTokens,
|
|
279
|
+
system: systemPrompt,
|
|
280
|
+
messages: [{
|
|
281
|
+
role: "user",
|
|
282
|
+
content: userPrompt
|
|
283
|
+
}]
|
|
284
|
+
})
|
|
285
|
+
});
|
|
286
|
+
if (!response.ok) {
|
|
287
|
+
const text = await response.text();
|
|
288
|
+
throw new Error(`MiniMax API error ${response.status}: ${text}`);
|
|
289
|
+
}
|
|
290
|
+
return ((await response.json()).content?.find((b) => b.type === "text"))?.text ?? "";
|
|
291
|
+
}
|
|
292
|
+
};
|
|
293
|
+
|
|
223
294
|
//#endregion
|
|
224
295
|
//#region src/providers/openrouter.ts
|
|
225
296
|
var OpenRouterProvider = class {
|
|
@@ -647,7 +718,8 @@ function createFallbackProvider(config, fallbackConfig) {
|
|
|
647
718
|
}
|
|
648
719
|
function createBaseProvider(config) {
|
|
649
720
|
switch (config.provider) {
|
|
650
|
-
case "
|
|
721
|
+
case "minimax": return new MinimaxProvider(requireEnvVar("MINIMAX_API_KEY"), config.model, config.maxTokens);
|
|
722
|
+
case "anthropic": return new AnthropicProvider(requireEnvVar("ANTHROPIC_API_KEY"), config.model, config.maxTokens, config.baseURL);
|
|
651
723
|
case "gemini": return new OpenRouterProvider(requireEnvVar("GEMINI_API_KEY"), config.model, config.maxTokens, "https://generativelanguage.googleapis.com/v1beta/openai/chat/completions");
|
|
652
724
|
case "openrouter": return new OpenRouterProvider(requireEnvVar("OPENROUTER_API_KEY"), config.model, config.maxTokens, "https://openrouter.ai/api/v1/chat/completions");
|
|
653
725
|
default: return new AgentSDKProvider();
|
|
@@ -2123,23 +2195,56 @@ function registerSearchFunction(sdk, kv) {
|
|
|
2123
2195
|
}, async (data) => {
|
|
2124
2196
|
const ctx = getContext();
|
|
2125
2197
|
const idx = getSearchIndex();
|
|
2198
|
+
if (typeof data?.query !== "string" || !data.query.trim()) throw new Error("mem::search: query must be a non-empty string");
|
|
2199
|
+
const query = data.query.trim();
|
|
2200
|
+
const MAX_LIMIT = 100;
|
|
2201
|
+
let effectiveLimit = 20;
|
|
2202
|
+
if (data.limit !== void 0) {
|
|
2203
|
+
if (!Number.isInteger(data.limit) || data.limit < 1) throw new Error("mem::search: limit must be a positive integer");
|
|
2204
|
+
effectiveLimit = Math.min(data.limit, MAX_LIMIT);
|
|
2205
|
+
}
|
|
2206
|
+
const projectFilter = typeof data.project === "string" && data.project.length > 0 ? data.project : void 0;
|
|
2207
|
+
const cwdFilter = typeof data.cwd === "string" && data.cwd.length > 0 ? data.cwd : void 0;
|
|
2126
2208
|
if (idx.size === 0) {
|
|
2127
2209
|
const count = await rebuildIndex(kv);
|
|
2128
2210
|
ctx.logger.info("Search index rebuilt", { entries: count });
|
|
2129
2211
|
}
|
|
2130
|
-
const
|
|
2131
|
-
const
|
|
2212
|
+
const filtering = !!(projectFilter || cwdFilter);
|
|
2213
|
+
const fetchLimit = filtering ? Math.max(effectiveLimit * 10, 100) : effectiveLimit;
|
|
2214
|
+
const results = idx.search(query, fetchLimit);
|
|
2215
|
+
const sessionCache = /* @__PURE__ */ new Map();
|
|
2216
|
+
const loadSession = async (sessionId) => {
|
|
2217
|
+
if (sessionCache.has(sessionId)) return sessionCache.get(sessionId);
|
|
2218
|
+
const s = await kv.get(KV.sessions, sessionId);
|
|
2219
|
+
sessionCache.set(sessionId, s ?? null);
|
|
2220
|
+
return s ?? null;
|
|
2221
|
+
};
|
|
2222
|
+
const candidates = [];
|
|
2132
2223
|
for (const r of results) {
|
|
2133
|
-
|
|
2224
|
+
if (candidates.length >= effectiveLimit) break;
|
|
2225
|
+
if (filtering) {
|
|
2226
|
+
const s = await loadSession(r.sessionId);
|
|
2227
|
+
if (!s) continue;
|
|
2228
|
+
if (projectFilter && s.project !== projectFilter) continue;
|
|
2229
|
+
if (cwdFilter && s.cwd !== cwdFilter) continue;
|
|
2230
|
+
}
|
|
2231
|
+
candidates.push(r);
|
|
2232
|
+
}
|
|
2233
|
+
const obsResults = await Promise.all(candidates.map((r) => kv.get(KV.observations(r.sessionId), r.obsId)));
|
|
2234
|
+
const enriched = [];
|
|
2235
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
2236
|
+
const obs = obsResults[i];
|
|
2134
2237
|
if (obs) enriched.push({
|
|
2135
2238
|
observation: obs,
|
|
2136
|
-
score:
|
|
2137
|
-
sessionId:
|
|
2239
|
+
score: candidates[i].score,
|
|
2240
|
+
sessionId: candidates[i].sessionId
|
|
2138
2241
|
});
|
|
2139
2242
|
}
|
|
2140
2243
|
ctx.logger.info("Search completed", {
|
|
2141
|
-
query
|
|
2142
|
-
results: enriched.length
|
|
2244
|
+
query,
|
|
2245
|
+
results: enriched.length,
|
|
2246
|
+
hasProjectFilter: !!projectFilter,
|
|
2247
|
+
hasCwdFilter: !!cwdFilter
|
|
2143
2248
|
});
|
|
2144
2249
|
return { results: enriched };
|
|
2145
2250
|
});
|
|
@@ -3805,7 +3910,7 @@ function registerAutoForgetFunction(sdk, kv) {
|
|
|
3805
3910
|
|
|
3806
3911
|
//#endregion
|
|
3807
3912
|
//#region src/version.ts
|
|
3808
|
-
const VERSION = "0.
|
|
3913
|
+
const VERSION = "0.8.1";
|
|
3809
3914
|
|
|
3810
3915
|
//#endregion
|
|
3811
3916
|
//#region src/functions/export-import.ts
|
|
@@ -3910,7 +4015,9 @@ function registerExportImportFunction(sdk, kv) {
|
|
|
3910
4015
|
"0.7.5",
|
|
3911
4016
|
"0.7.6",
|
|
3912
4017
|
"0.7.7",
|
|
3913
|
-
"0.7.9"
|
|
4018
|
+
"0.7.9",
|
|
4019
|
+
"0.8.0",
|
|
4020
|
+
"0.8.1"
|
|
3914
4021
|
]).has(importData.version)) return {
|
|
3915
4022
|
success: false,
|
|
3916
4023
|
error: `Unsupported export version: ${importData.version}`
|
|
@@ -10033,9 +10140,32 @@ function registerApiTriggers(sdk, kv, secret, metricsStore, provider) {
|
|
|
10033
10140
|
sdk.registerFunction({ id: "api::search" }, async (req) => {
|
|
10034
10141
|
const authErr = checkAuth$1(req, secret);
|
|
10035
10142
|
if (authErr) return authErr;
|
|
10143
|
+
const body = req.body ?? {};
|
|
10144
|
+
if (typeof body.query !== "string" || !body.query.trim()) return {
|
|
10145
|
+
status_code: 400,
|
|
10146
|
+
body: { error: "query is required and must be a non-empty string" }
|
|
10147
|
+
};
|
|
10148
|
+
if (body.limit !== void 0 && (!Number.isInteger(body.limit) || body.limit < 1)) return {
|
|
10149
|
+
status_code: 400,
|
|
10150
|
+
body: { error: "limit must be a positive integer" }
|
|
10151
|
+
};
|
|
10152
|
+
if (body.project !== void 0 && typeof body.project !== "string") return {
|
|
10153
|
+
status_code: 400,
|
|
10154
|
+
body: { error: "project must be a string" }
|
|
10155
|
+
};
|
|
10156
|
+
if (body.cwd !== void 0 && typeof body.cwd !== "string") return {
|
|
10157
|
+
status_code: 400,
|
|
10158
|
+
body: { error: "cwd must be a string" }
|
|
10159
|
+
};
|
|
10160
|
+
const payload = {
|
|
10161
|
+
query: body.query.trim(),
|
|
10162
|
+
limit: body.limit,
|
|
10163
|
+
project: body.project,
|
|
10164
|
+
cwd: body.cwd
|
|
10165
|
+
};
|
|
10036
10166
|
return {
|
|
10037
10167
|
status_code: 200,
|
|
10038
|
-
body: await sdk.trigger("mem::search",
|
|
10168
|
+
body: await sdk.trigger("mem::search", payload)
|
|
10039
10169
|
};
|
|
10040
10170
|
});
|
|
10041
10171
|
sdk.registerTrigger({
|
|
@@ -14336,9 +14466,11 @@ function startViewerServer(port, _kv, _sdk, secret, restPort) {
|
|
|
14336
14466
|
if (method === "GET" && (pathname === "/" || pathname === "/viewer" || pathname === "/agentmemory/viewer")) {
|
|
14337
14467
|
const base = dirname(fileURLToPath(import.meta.url));
|
|
14338
14468
|
const candidates = [
|
|
14339
|
-
join(base, "
|
|
14469
|
+
join(base, "index.html"),
|
|
14470
|
+
join(base, "viewer", "index.html"),
|
|
14340
14471
|
join(base, "..", "viewer", "index.html"),
|
|
14341
|
-
join(base, "viewer", "index.html")
|
|
14472
|
+
join(base, "..", "src", "viewer", "index.html"),
|
|
14473
|
+
join(base, "..", "dist", "viewer", "index.html")
|
|
14342
14474
|
];
|
|
14343
14475
|
for (const p of candidates) try {
|
|
14344
14476
|
const html = readFileSync(p, "utf-8");
|