@jcyamacho/agent-memory 0.0.3 → 0.0.4
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 +3 -4
- package/dist/index.js +68 -78
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,8 +77,8 @@ short phrases. Each term is matched independently — more terms cast a wider ne
|
|
|
77
77
|
and results matching multiple terms rank higher. Stemming is applied
|
|
78
78
|
automatically, so exact word forms are not required.
|
|
79
79
|
|
|
80
|
-
Use `
|
|
81
|
-
|
|
80
|
+
Use `workspace` to bias ranking toward the current project. Use `created_*`
|
|
81
|
+
only for exact scoping.
|
|
82
82
|
```
|
|
83
83
|
|
|
84
84
|
## What It Stores
|
|
@@ -116,8 +116,7 @@ Inputs:
|
|
|
116
116
|
- `terms` -> 2-5 distinctive terms or short phrases that should appear in the
|
|
117
117
|
memory content; avoid full natural-language questions
|
|
118
118
|
- `limit` -> maximum results to return
|
|
119
|
-
- `
|
|
120
|
-
- `filter_workspace` -> exact workspace filter
|
|
119
|
+
- `workspace` -> workspace or repo path; biases ranking toward this workspace
|
|
121
120
|
- `created_after` -> ISO 8601 lower bound
|
|
122
121
|
- `created_before` -> ISO 8601 upper bound
|
|
123
122
|
|
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.4";
|
|
12468
12468
|
|
|
12469
12469
|
// src/config.ts
|
|
12470
12470
|
import { homedir } from "node:os";
|
|
@@ -19881,6 +19881,9 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
19881
19881
|
}
|
|
19882
19882
|
};
|
|
19883
19883
|
|
|
19884
|
+
// src/memory-service.ts
|
|
19885
|
+
import { randomUUID } from "node:crypto";
|
|
19886
|
+
|
|
19884
19887
|
// src/errors.ts
|
|
19885
19888
|
class MemoryError extends Error {
|
|
19886
19889
|
code;
|
|
@@ -19905,6 +19908,63 @@ class PersistenceError extends MemoryError {
|
|
|
19905
19908
|
}
|
|
19906
19909
|
}
|
|
19907
19910
|
|
|
19911
|
+
// src/memory-service.ts
|
|
19912
|
+
var DEFAULT_LIMIT = 15;
|
|
19913
|
+
var MAX_LIMIT = 50;
|
|
19914
|
+
|
|
19915
|
+
class MemoryService {
|
|
19916
|
+
repository;
|
|
19917
|
+
constructor(repository) {
|
|
19918
|
+
this.repository = repository;
|
|
19919
|
+
}
|
|
19920
|
+
async save(input) {
|
|
19921
|
+
const content = input.content.trim();
|
|
19922
|
+
if (!content) {
|
|
19923
|
+
throw new ValidationError("Memory content is required.");
|
|
19924
|
+
}
|
|
19925
|
+
const now = new Date;
|
|
19926
|
+
const memory = {
|
|
19927
|
+
id: randomUUID(),
|
|
19928
|
+
content,
|
|
19929
|
+
workspace: normalizeOptionalString(input.workspace),
|
|
19930
|
+
createdAt: now,
|
|
19931
|
+
updatedAt: now
|
|
19932
|
+
};
|
|
19933
|
+
return this.repository.save(memory);
|
|
19934
|
+
}
|
|
19935
|
+
async search(input) {
|
|
19936
|
+
const terms = normalizeTerms(input.terms);
|
|
19937
|
+
if (terms.length === 0) {
|
|
19938
|
+
throw new ValidationError("At least one search term is required.");
|
|
19939
|
+
}
|
|
19940
|
+
const normalizedQuery = {
|
|
19941
|
+
terms,
|
|
19942
|
+
limit: normalizeLimit(input.limit),
|
|
19943
|
+
workspace: normalizeOptionalString(input.workspace),
|
|
19944
|
+
createdAfter: input.createdAfter,
|
|
19945
|
+
createdBefore: input.createdBefore
|
|
19946
|
+
};
|
|
19947
|
+
return this.repository.search(normalizedQuery);
|
|
19948
|
+
}
|
|
19949
|
+
}
|
|
19950
|
+
var normalizeLimit = (value) => {
|
|
19951
|
+
if (value === undefined) {
|
|
19952
|
+
return DEFAULT_LIMIT;
|
|
19953
|
+
}
|
|
19954
|
+
if (!Number.isInteger(value) || value < 1 || value > MAX_LIMIT) {
|
|
19955
|
+
throw new ValidationError(`Limit must be an integer between 1 and ${MAX_LIMIT}.`);
|
|
19956
|
+
}
|
|
19957
|
+
return value;
|
|
19958
|
+
};
|
|
19959
|
+
var normalizeOptionalString = (value) => {
|
|
19960
|
+
const trimmed = value?.trim();
|
|
19961
|
+
return trimmed ? trimmed : undefined;
|
|
19962
|
+
};
|
|
19963
|
+
var normalizeTerms = (terms) => {
|
|
19964
|
+
const normalizedTerms = terms.map((term) => term.trim()).filter(Boolean);
|
|
19965
|
+
return [...new Set(normalizedTerms)];
|
|
19966
|
+
};
|
|
19967
|
+
|
|
19908
19968
|
// src/tools/shared.ts
|
|
19909
19969
|
var toMcpError = (error2) => {
|
|
19910
19970
|
if (error2 instanceof McpError) {
|
|
@@ -19933,9 +19993,8 @@ var parseOptionalDate = (value, fieldName) => {
|
|
|
19933
19993
|
// src/tools/recall.ts
|
|
19934
19994
|
var recallInputSchema = {
|
|
19935
19995
|
terms: array(string2()).min(1).describe("Search terms to match against remembered content. Use distinctive keywords, IDs, names, file names, or short phrases as separate items."),
|
|
19936
|
-
limit: number2().int().min(1).max(
|
|
19937
|
-
|
|
19938
|
-
filter_workspace: string2().optional().describe("Only return memories from this exact workspace or repository path."),
|
|
19996
|
+
limit: number2().int().min(1).max(MAX_LIMIT).optional().describe("Maximum number of memory results to return. Use a small number when you only need the best matches."),
|
|
19997
|
+
workspace: string2().optional().describe("Workspace or repository path. Memories from this workspace rank higher, but other workspaces are not excluded."),
|
|
19939
19998
|
created_after: string2().optional().describe("Only return memories created at or after this ISO 8601 timestamp."),
|
|
19940
19999
|
created_before: string2().optional().describe("Only return memories created at or before this ISO 8601 timestamp.")
|
|
19941
20000
|
};
|
|
@@ -19953,13 +20012,12 @@ var registerRecallTool = (server, memoryService) => {
|
|
|
19953
20012
|
description: "Retrieve previously remembered context that may help with the current task. Use it for user preferences, project facts, prior decisions, constraints, or earlier conversation details.",
|
|
19954
20013
|
inputSchema: recallInputSchema,
|
|
19955
20014
|
outputSchema: recallOutputSchema
|
|
19956
|
-
}, async ({ terms, limit,
|
|
20015
|
+
}, async ({ terms, limit, workspace, created_after, created_before }) => {
|
|
19957
20016
|
try {
|
|
19958
20017
|
const results = await memoryService.search({
|
|
19959
20018
|
terms,
|
|
19960
20019
|
limit,
|
|
19961
|
-
|
|
19962
|
-
filterWorkspace: filter_workspace,
|
|
20020
|
+
workspace,
|
|
19963
20021
|
createdAfter: parseOptionalDate(created_after, "created_after"),
|
|
19964
20022
|
createdBefore: parseOptionalDate(created_before, "created_before")
|
|
19965
20023
|
});
|
|
@@ -20041,66 +20099,6 @@ var createMcpServer = (memoryService, version3) => {
|
|
|
20041
20099
|
return server;
|
|
20042
20100
|
};
|
|
20043
20101
|
|
|
20044
|
-
// src/memory-service.ts
|
|
20045
|
-
import { randomUUID } from "node:crypto";
|
|
20046
|
-
var DEFAULT_LIMIT = 5;
|
|
20047
|
-
var MAX_LIMIT = 20;
|
|
20048
|
-
|
|
20049
|
-
class MemoryService {
|
|
20050
|
-
repository;
|
|
20051
|
-
constructor(repository) {
|
|
20052
|
-
this.repository = repository;
|
|
20053
|
-
}
|
|
20054
|
-
async save(input) {
|
|
20055
|
-
const content = input.content.trim();
|
|
20056
|
-
if (!content) {
|
|
20057
|
-
throw new ValidationError("Memory content is required.");
|
|
20058
|
-
}
|
|
20059
|
-
const now = new Date;
|
|
20060
|
-
const memory = {
|
|
20061
|
-
id: randomUUID(),
|
|
20062
|
-
content,
|
|
20063
|
-
workspace: normalizeOptionalString(input.workspace),
|
|
20064
|
-
createdAt: now,
|
|
20065
|
-
updatedAt: now
|
|
20066
|
-
};
|
|
20067
|
-
return this.repository.save(memory);
|
|
20068
|
-
}
|
|
20069
|
-
async search(input) {
|
|
20070
|
-
const terms = normalizeTerms(input.terms);
|
|
20071
|
-
if (terms.length === 0) {
|
|
20072
|
-
throw new ValidationError("At least one search term is required.");
|
|
20073
|
-
}
|
|
20074
|
-
const normalizedQuery = {
|
|
20075
|
-
terms,
|
|
20076
|
-
limit: normalizeLimit(input.limit),
|
|
20077
|
-
preferredWorkspace: normalizeOptionalString(input.preferredWorkspace),
|
|
20078
|
-
filterWorkspace: normalizeOptionalString(input.filterWorkspace),
|
|
20079
|
-
createdAfter: input.createdAfter,
|
|
20080
|
-
createdBefore: input.createdBefore
|
|
20081
|
-
};
|
|
20082
|
-
const results = await this.repository.search(normalizedQuery);
|
|
20083
|
-
return results.slice(0, normalizedQuery.limit);
|
|
20084
|
-
}
|
|
20085
|
-
}
|
|
20086
|
-
var normalizeLimit = (value) => {
|
|
20087
|
-
if (value === undefined) {
|
|
20088
|
-
return DEFAULT_LIMIT;
|
|
20089
|
-
}
|
|
20090
|
-
if (!Number.isInteger(value) || value < 1 || value > MAX_LIMIT) {
|
|
20091
|
-
throw new ValidationError(`Limit must be an integer between 1 and ${MAX_LIMIT}.`);
|
|
20092
|
-
}
|
|
20093
|
-
return value;
|
|
20094
|
-
};
|
|
20095
|
-
var normalizeOptionalString = (value) => {
|
|
20096
|
-
const trimmed = value?.trim();
|
|
20097
|
-
return trimmed ? trimmed : undefined;
|
|
20098
|
-
};
|
|
20099
|
-
var normalizeTerms = (terms) => {
|
|
20100
|
-
const normalizedTerms = terms.map((term) => term.trim()).filter(Boolean);
|
|
20101
|
-
return [...new Set(normalizedTerms)];
|
|
20102
|
-
};
|
|
20103
|
-
|
|
20104
20102
|
// src/sqlite-db.ts
|
|
20105
20103
|
import { mkdirSync } from "node:fs";
|
|
20106
20104
|
import { dirname } from "node:path";
|
|
@@ -20167,9 +20165,6 @@ var initializeMemoryDatabase = (database) => {
|
|
|
20167
20165
|
};
|
|
20168
20166
|
|
|
20169
20167
|
// src/sqlite-repository.ts
|
|
20170
|
-
var CANDIDATE_MULTIPLIER = 5;
|
|
20171
|
-
var MIN_CANDIDATES = 25;
|
|
20172
|
-
var MAX_CANDIDATES = 100;
|
|
20173
20168
|
var WORKSPACE_BIAS = 0.1;
|
|
20174
20169
|
|
|
20175
20170
|
class SqliteMemoryRepository {
|
|
@@ -20206,17 +20201,13 @@ class SqliteMemoryRepository {
|
|
|
20206
20201
|
const selectParams = [];
|
|
20207
20202
|
const whereParams = [toFtsQuery(query.terms)];
|
|
20208
20203
|
let scoreExpr;
|
|
20209
|
-
if (query.
|
|
20204
|
+
if (query.workspace) {
|
|
20210
20205
|
scoreExpr = "MAX(0, -bm25(memories_fts) + CASE WHEN m.workspace = ? THEN ? ELSE 0.0 END)";
|
|
20211
|
-
selectParams.push(query.
|
|
20206
|
+
selectParams.push(query.workspace, WORKSPACE_BIAS);
|
|
20212
20207
|
} else {
|
|
20213
20208
|
scoreExpr = "MAX(0, -bm25(memories_fts))";
|
|
20214
20209
|
}
|
|
20215
20210
|
const whereClauses = ["memories_fts MATCH ?"];
|
|
20216
|
-
if (query.filterWorkspace) {
|
|
20217
|
-
whereClauses.push("m.workspace = ?");
|
|
20218
|
-
whereParams.push(query.filterWorkspace);
|
|
20219
|
-
}
|
|
20220
20211
|
if (query.createdAfter) {
|
|
20221
20212
|
whereClauses.push("m.created_at >= ?");
|
|
20222
20213
|
whereParams.push(query.createdAfter.getTime());
|
|
@@ -20225,7 +20216,7 @@ class SqliteMemoryRepository {
|
|
|
20225
20216
|
whereClauses.push("m.created_at <= ?");
|
|
20226
20217
|
whereParams.push(query.createdBefore.getTime());
|
|
20227
20218
|
}
|
|
20228
|
-
const params = [...selectParams, ...whereParams,
|
|
20219
|
+
const params = [...selectParams, ...whereParams, query.limit];
|
|
20229
20220
|
const statement = this.database.prepare(`
|
|
20230
20221
|
SELECT
|
|
20231
20222
|
m.id,
|
|
@@ -20254,7 +20245,6 @@ class SqliteMemoryRepository {
|
|
|
20254
20245
|
}
|
|
20255
20246
|
}
|
|
20256
20247
|
}
|
|
20257
|
-
var toCandidateLimit = (limit) => Math.min(Math.max(limit * CANDIDATE_MULTIPLIER, MIN_CANDIDATES), MAX_CANDIDATES);
|
|
20258
20248
|
var toFtsQuery = (terms) => terms.map(toFtsTerm).join(" OR ");
|
|
20259
20249
|
var toFtsTerm = (term) => {
|
|
20260
20250
|
const escaped = term.replaceAll('"', '""');
|