@jcyamacho/agent-memory 0.0.18 → 0.0.19
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 +11 -8
- package/dist/index.js +36 -30
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,10 +49,11 @@ Optional LLM instructions to reinforce the MCP's built-in guidance:
|
|
|
49
49
|
## Agent Memory
|
|
50
50
|
|
|
51
51
|
- Use `memory_recall` at conversation start and before design choices,
|
|
52
|
-
conventions, or
|
|
52
|
+
conventions, edge cases, or saving memory.
|
|
53
53
|
- Query `memory_recall` with 2-5 short anchor-heavy terms or exact phrases,
|
|
54
54
|
not full questions or sentences.
|
|
55
|
-
- Pass `workspace` for project-scoped memory. Omit it only for
|
|
55
|
+
- Pass `workspace` for project-scoped memory. Omit it only for facts that
|
|
56
|
+
apply across projects.
|
|
56
57
|
- Use `memory_remember` to save one durable fact when the user states a stable
|
|
57
58
|
preference, correction, or reusable project decision.
|
|
58
59
|
- If the fact already exists, use `memory_revise` instead of creating a duplicate.
|
|
@@ -83,15 +84,15 @@ memories:
|
|
|
83
84
|
|
|
84
85
|
1. **Text relevance** is the primary signal -- memories whose content best
|
|
85
86
|
matches your search terms rank highest.
|
|
86
|
-
2. **
|
|
87
|
-
|
|
87
|
+
2. **Workspace match** is the next strongest signal. When you pass
|
|
88
|
+
`workspace`, exact matches rank highest and all other scoped workspaces rank
|
|
89
|
+
below exact matches.
|
|
90
|
+
3. **Embedding similarity** is a secondary signal. Recall builds an embedding
|
|
91
|
+
from your normalized search terms and boosts memories whose stored
|
|
88
92
|
embeddings are most semantically similar.
|
|
89
|
-
3. **Workspace match** is a strong secondary signal. When you pass
|
|
90
|
-
`workspace`, exact matches rank highest, sibling repositories get a small
|
|
91
|
-
boost, and unrelated workspaces rank lowest.
|
|
92
93
|
4. **Global memories** (saved without a workspace) are treated as relevant
|
|
93
94
|
everywhere. When you pass `workspace`, they rank below exact workspace
|
|
94
|
-
matches and above
|
|
95
|
+
matches and above memories from other workspaces.
|
|
95
96
|
5. **Recency** is a minor tiebreaker -- newer memories rank slightly above older
|
|
96
97
|
ones when other signals are equal.
|
|
97
98
|
|
|
@@ -102,6 +103,8 @@ memories without a workspace only when they apply across all projects.
|
|
|
102
103
|
When you save a memory from a git worktree, `agent-memory` stores the main repo
|
|
103
104
|
root as the workspace. `recall` applies the same normalization to incoming
|
|
104
105
|
workspace queries so linked worktrees still match repo-scoped memories exactly.
|
|
106
|
+
When that happens, recall returns the queried workspace value so callers can
|
|
107
|
+
treat the match as belonging to their current worktree context.
|
|
105
108
|
|
|
106
109
|
## Configuration
|
|
107
110
|
|
package/dist/index.js
CHANGED
|
@@ -12464,7 +12464,7 @@ class StdioServerTransport {
|
|
|
12464
12464
|
}
|
|
12465
12465
|
}
|
|
12466
12466
|
// package.json
|
|
12467
|
-
var version2 = "0.0.
|
|
12467
|
+
var version2 = "0.0.19";
|
|
12468
12468
|
|
|
12469
12469
|
// src/config.ts
|
|
12470
12470
|
import { homedir } from "node:os";
|
|
@@ -20086,15 +20086,14 @@ function registerForgetTool(server, memory) {
|
|
|
20086
20086
|
var toNormalizedScore = (value) => value;
|
|
20087
20087
|
|
|
20088
20088
|
// src/ranking.ts
|
|
20089
|
-
var RETRIEVAL_SCORE_WEIGHT =
|
|
20090
|
-
var EMBEDDING_SIMILARITY_WEIGHT =
|
|
20091
|
-
var WORKSPACE_MATCH_WEIGHT =
|
|
20092
|
-
var RECENCY_WEIGHT =
|
|
20089
|
+
var RETRIEVAL_SCORE_WEIGHT = 9;
|
|
20090
|
+
var EMBEDDING_SIMILARITY_WEIGHT = 4;
|
|
20091
|
+
var WORKSPACE_MATCH_WEIGHT = 5;
|
|
20092
|
+
var RECENCY_WEIGHT = 1;
|
|
20093
20093
|
var MAX_COMPOSITE_SCORE = RETRIEVAL_SCORE_WEIGHT + EMBEDDING_SIMILARITY_WEIGHT + WORKSPACE_MATCH_WEIGHT + RECENCY_WEIGHT;
|
|
20094
20094
|
var GLOBAL_WORKSPACE_SCORE = 0.5;
|
|
20095
|
-
var SIBLING_WORKSPACE_SCORE = 0.25;
|
|
20096
20095
|
function rerankSearchResults(results, workspace, queryEmbedding) {
|
|
20097
|
-
if (results.length
|
|
20096
|
+
if (results.length === 0) {
|
|
20098
20097
|
return results;
|
|
20099
20098
|
}
|
|
20100
20099
|
const normalizedQueryWs = workspace ? normalizeWorkspacePath(workspace) : undefined;
|
|
@@ -20132,14 +20131,7 @@ function computeWorkspaceScore(memoryWs, queryWs) {
|
|
|
20132
20131
|
if (normalizedMemoryWs === queryWs) {
|
|
20133
20132
|
return 1;
|
|
20134
20133
|
}
|
|
20135
|
-
|
|
20136
|
-
const memoryLastSlashIndex = normalizedMemoryWs.lastIndexOf("/");
|
|
20137
|
-
if (queryLastSlashIndex <= 0 || memoryLastSlashIndex <= 0) {
|
|
20138
|
-
return 0;
|
|
20139
|
-
}
|
|
20140
|
-
const queryParent = queryWs.slice(0, queryLastSlashIndex);
|
|
20141
|
-
const memoryParent = normalizedMemoryWs.slice(0, memoryLastSlashIndex);
|
|
20142
|
-
return memoryParent === queryParent ? SIBLING_WORKSPACE_SCORE : 0;
|
|
20134
|
+
return 0;
|
|
20143
20135
|
}
|
|
20144
20136
|
|
|
20145
20137
|
// src/memory-service.ts
|
|
@@ -20211,6 +20203,7 @@ class MemoryService {
|
|
|
20211
20203
|
throw new ValidationError("At least one search term is required.");
|
|
20212
20204
|
}
|
|
20213
20205
|
const requestedLimit = normalizeLimit(input.limit);
|
|
20206
|
+
const queryWorkspace = normalizeOptionalString(input.workspace);
|
|
20214
20207
|
const workspace = await this.workspaceResolver.resolve(input.workspace);
|
|
20215
20208
|
const normalizedQuery = {
|
|
20216
20209
|
terms,
|
|
@@ -20222,7 +20215,7 @@ class MemoryService {
|
|
|
20222
20215
|
this.repository.search(normalizedQuery),
|
|
20223
20216
|
this.embeddingService.createVector(terms.join(" "))
|
|
20224
20217
|
]);
|
|
20225
|
-
return rerankSearchResults(results, workspace, queryEmbedding).slice(0, requestedLimit).map(toPublicSearchResult);
|
|
20218
|
+
return rerankSearchResults(results, workspace, queryEmbedding).slice(0, requestedLimit).map((result) => toPublicSearchResult(remapSearchResultWorkspace(result, workspace, queryWorkspace)));
|
|
20226
20219
|
}
|
|
20227
20220
|
}
|
|
20228
20221
|
function toPublicMemoryRecord(memory) {
|
|
@@ -20272,12 +20265,25 @@ function normalizeTerms(terms) {
|
|
|
20272
20265
|
const normalizedTerms = terms.map((term) => term.trim()).filter(Boolean);
|
|
20273
20266
|
return [...new Set(normalizedTerms)];
|
|
20274
20267
|
}
|
|
20268
|
+
function normalizeOptionalString(value) {
|
|
20269
|
+
const trimmed = value?.trim();
|
|
20270
|
+
return trimmed ? trimmed : undefined;
|
|
20271
|
+
}
|
|
20272
|
+
function remapSearchResultWorkspace(result, canonicalWorkspace, queryWorkspace) {
|
|
20273
|
+
if (!queryWorkspace || !canonicalWorkspace || result.workspace !== canonicalWorkspace) {
|
|
20274
|
+
return result;
|
|
20275
|
+
}
|
|
20276
|
+
return {
|
|
20277
|
+
...result,
|
|
20278
|
+
workspace: queryWorkspace
|
|
20279
|
+
};
|
|
20280
|
+
}
|
|
20275
20281
|
|
|
20276
20282
|
// src/mcp/tools/recall.ts
|
|
20277
20283
|
var recallInputSchema = {
|
|
20278
|
-
terms: array(string2()).min(1).describe("
|
|
20284
|
+
terms: array(string2()).min(1).describe("2-5 short anchor-heavy terms or exact phrases. Prefer identifiers, commands, file paths, and exact wording likely to appear in the memory."),
|
|
20279
20285
|
limit: number2().int().min(1).max(MAX_RECALL_LIMIT).optional().describe("Maximum matches to return. Keep this small when you only need the strongest hits."),
|
|
20280
|
-
workspace: string2().optional().describe("
|
|
20286
|
+
workspace: string2().optional().describe("Current working directory for project-scoped recall. Omit for cross-project recall."),
|
|
20281
20287
|
updated_after: string2().optional().describe("Only return memories updated on or after this ISO 8601 timestamp."),
|
|
20282
20288
|
updated_before: string2().optional().describe("Only return memories updated on or before this ISO 8601 timestamp.")
|
|
20283
20289
|
};
|
|
@@ -20296,7 +20302,7 @@ function registerRecallTool(server, memory) {
|
|
|
20296
20302
|
readOnlyHint: true,
|
|
20297
20303
|
openWorldHint: false
|
|
20298
20304
|
},
|
|
20299
|
-
description: "
|
|
20305
|
+
description: "Retrieve memories relevant to the current task or check whether a fact already exists before saving. Use at conversation start and before design choices. Pass short anchor-heavy `terms` and `workspace` when available. Results reflect the queried workspace context when applicable. Returns `<memories>...</memories>` or a no-match hint.",
|
|
20300
20306
|
inputSchema: recallInputSchema
|
|
20301
20307
|
}, async ({ terms, limit, workspace, updated_after, updated_before }) => {
|
|
20302
20308
|
try {
|
|
@@ -20323,7 +20329,7 @@ ${results.map(toMemoryXml).join(`
|
|
|
20323
20329
|
// src/mcp/tools/remember.ts
|
|
20324
20330
|
var rememberInputSchema = {
|
|
20325
20331
|
content: string2().describe("One new durable fact to save. Use a self-contained sentence or short note."),
|
|
20326
|
-
workspace: string2().optional().describe("
|
|
20332
|
+
workspace: string2().optional().describe("Current working directory for project-scoped memory. Omit for facts that apply across projects.")
|
|
20327
20333
|
};
|
|
20328
20334
|
function registerRememberTool(server, memory) {
|
|
20329
20335
|
server.registerTool("remember", {
|
|
@@ -20333,7 +20339,7 @@ function registerRememberTool(server, memory) {
|
|
|
20333
20339
|
idempotentHint: false,
|
|
20334
20340
|
openWorldHint: false
|
|
20335
20341
|
},
|
|
20336
|
-
description: 'Save one new durable fact for later recall. Use for stable preferences,
|
|
20342
|
+
description: 'Save one new durable fact for later recall. Use for stable preferences, reusable decisions, and project context not obvious from code or git history. If the fact already exists, use `revise` instead. Returns `<memory id="..." />`.',
|
|
20337
20343
|
inputSchema: rememberInputSchema
|
|
20338
20344
|
}, async ({ content, workspace }) => {
|
|
20339
20345
|
try {
|
|
@@ -20353,7 +20359,7 @@ function registerRememberTool(server, memory) {
|
|
|
20353
20359
|
// src/mcp/tools/revise.ts
|
|
20354
20360
|
var reviseInputSchema = {
|
|
20355
20361
|
id: string2().describe("Memory id to update. Use an id returned by `recall`."),
|
|
20356
|
-
content: string2().describe("Corrected replacement text for that memory.
|
|
20362
|
+
content: string2().describe("Corrected replacement text for that memory.")
|
|
20357
20363
|
};
|
|
20358
20364
|
function registerReviseTool(server, memory) {
|
|
20359
20365
|
server.registerTool("revise", {
|
|
@@ -20363,7 +20369,7 @@ function registerReviseTool(server, memory) {
|
|
|
20363
20369
|
idempotentHint: false,
|
|
20364
20370
|
openWorldHint: false
|
|
20365
20371
|
},
|
|
20366
|
-
description: 'Update one existing memory when the same fact still applies but its wording or details changed. Use after `recall` when you already have the memory id.
|
|
20372
|
+
description: 'Update one existing memory when the same fact still applies but its wording or details changed. Use after `recall` when you already have the memory id. Returns `<memory id="..." updated_at="..." />`.',
|
|
20367
20373
|
inputSchema: reviseInputSchema
|
|
20368
20374
|
}, async ({ id, content }) => {
|
|
20369
20375
|
try {
|
|
@@ -20385,11 +20391,11 @@ function registerReviseTool(server, memory) {
|
|
|
20385
20391
|
// src/mcp/server.ts
|
|
20386
20392
|
var SERVER_INSTRUCTIONS = [
|
|
20387
20393
|
"Use this server only for durable memory that should survive across turns: stable preferences, corrections, reusable decisions, and project context not obvious from code or git history.",
|
|
20388
|
-
"Use `recall` at conversation start, before design choices, and before saving memory.",
|
|
20389
|
-
"Use `remember`
|
|
20390
|
-
"Use `forget` only when a memory is wrong or
|
|
20391
|
-
"Pass workspace for project-scoped memory. Omit it only for
|
|
20392
|
-
"Do not store secrets
|
|
20394
|
+
"Use `recall` at conversation start, before design choices, and before saving or revising memory.",
|
|
20395
|
+
"Use `remember` for one new durable fact. Use `revise` when the fact already exists but needs correction.",
|
|
20396
|
+
"Use `forget` only when a memory is wrong or obsolete.",
|
|
20397
|
+
"Pass workspace for project-scoped memory. Omit it only for facts that apply across projects.",
|
|
20398
|
+
"Do not store secrets, temporary task state, or facts obvious from current code or git history."
|
|
20393
20399
|
].join(" ");
|
|
20394
20400
|
function createMcpServer(memory, version3) {
|
|
20395
20401
|
const server = new McpServer({
|
|
@@ -24244,7 +24250,7 @@ function createGitWorkspaceResolver(options = {}) {
|
|
|
24244
24250
|
const cache = new Map;
|
|
24245
24251
|
return {
|
|
24246
24252
|
async resolve(workspace) {
|
|
24247
|
-
const trimmed =
|
|
24253
|
+
const trimmed = normalizeOptionalString2(workspace);
|
|
24248
24254
|
if (!trimmed) {
|
|
24249
24255
|
return;
|
|
24250
24256
|
}
|
|
@@ -24275,7 +24281,7 @@ async function defaultGetGitCommonDir(cwd) {
|
|
|
24275
24281
|
});
|
|
24276
24282
|
return stdout.trim();
|
|
24277
24283
|
}
|
|
24278
|
-
function
|
|
24284
|
+
function normalizeOptionalString2(value) {
|
|
24279
24285
|
const trimmed = value?.trim();
|
|
24280
24286
|
return trimmed ? trimmed : undefined;
|
|
24281
24287
|
}
|