@smyslenny/agent-memory 4.0.0-alpha.1 → 4.2.0
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/CHANGELOG.md +38 -0
- package/dist/bin/agent-memory.js +1171 -886
- package/dist/bin/agent-memory.js.map +1 -1
- package/dist/index.d.ts +52 -7
- package/dist/index.js +159 -16
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +175 -29
- package/dist/mcp/server.js.map +1 -1
- package/docs/design/.next-id +1 -0
- package/docs/design/0016-v41-warm-boot-surface-emotion.md +228 -0
- package/package.json +1 -1
package/dist/mcp/server.js
CHANGED
|
@@ -89,6 +89,11 @@ function migrateDatabase(db, from, to) {
|
|
|
89
89
|
v = 5;
|
|
90
90
|
continue;
|
|
91
91
|
}
|
|
92
|
+
if (v === 5) {
|
|
93
|
+
migrateV5ToV6(db);
|
|
94
|
+
v = 6;
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
92
97
|
throw new Error(`Unsupported schema migration path: v${from} \u2192 v${to} (stuck at v${v})`);
|
|
93
98
|
}
|
|
94
99
|
}
|
|
@@ -174,6 +179,8 @@ function inferSchemaVersion(db) {
|
|
|
174
179
|
const hasV4Embeddings = hasEmbeddings && tableHasColumn(db, "embeddings", "provider_id") && tableHasColumn(db, "embeddings", "status") && tableHasColumn(db, "embeddings", "content_hash") && tableHasColumn(db, "embeddings", "id");
|
|
175
180
|
const hasMaintenanceJobs = tableExists(db, "maintenance_jobs");
|
|
176
181
|
const hasFeedbackEvents = tableExists(db, "feedback_events");
|
|
182
|
+
const hasEmotionTag = tableHasColumn(db, "memories", "emotion_tag");
|
|
183
|
+
if (hasAgentScopedPaths && hasAgentScopedLinks && hasV4Embeddings && hasMaintenanceJobs && hasFeedbackEvents && hasEmotionTag) return 6;
|
|
177
184
|
if (hasAgentScopedPaths && hasAgentScopedLinks && hasV4Embeddings && hasMaintenanceJobs && hasFeedbackEvents) return 5;
|
|
178
185
|
if (hasAgentScopedPaths && hasAgentScopedLinks && hasV4Embeddings) return 4;
|
|
179
186
|
if (hasAgentScopedPaths && hasAgentScopedLinks && hasEmbeddings) return 3;
|
|
@@ -200,6 +207,9 @@ function ensureIndexes(db) {
|
|
|
200
207
|
if (tableExists(db, "maintenance_jobs")) {
|
|
201
208
|
db.exec("CREATE INDEX IF NOT EXISTS idx_maintenance_jobs_phase_status ON maintenance_jobs(phase, status, started_at DESC);");
|
|
202
209
|
}
|
|
210
|
+
if (tableHasColumn(db, "memories", "emotion_tag")) {
|
|
211
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_memories_emotion_tag ON memories(emotion_tag) WHERE emotion_tag IS NOT NULL;");
|
|
212
|
+
}
|
|
203
213
|
if (tableExists(db, "feedback_events")) {
|
|
204
214
|
db.exec("CREATE INDEX IF NOT EXISTS idx_feedback_events_memory ON feedback_events(memory_id, created_at DESC);");
|
|
205
215
|
if (tableHasColumn(db, "feedback_events", "agent_id") && tableHasColumn(db, "feedback_events", "source")) {
|
|
@@ -333,11 +343,30 @@ function migrateV4ToV5(db) {
|
|
|
333
343
|
throw e;
|
|
334
344
|
}
|
|
335
345
|
}
|
|
346
|
+
function migrateV5ToV6(db) {
|
|
347
|
+
if (tableHasColumn(db, "memories", "emotion_tag")) {
|
|
348
|
+
db.prepare("INSERT OR REPLACE INTO schema_meta (key, value) VALUES ('version', ?)").run(String(6));
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
try {
|
|
352
|
+
db.exec("BEGIN");
|
|
353
|
+
db.exec("ALTER TABLE memories ADD COLUMN emotion_tag TEXT;");
|
|
354
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_memories_emotion_tag ON memories(emotion_tag) WHERE emotion_tag IS NOT NULL;");
|
|
355
|
+
db.prepare("INSERT OR REPLACE INTO schema_meta (key, value) VALUES ('version', ?)").run(String(6));
|
|
356
|
+
db.exec("COMMIT");
|
|
357
|
+
} catch (e) {
|
|
358
|
+
try {
|
|
359
|
+
db.exec("ROLLBACK");
|
|
360
|
+
} catch {
|
|
361
|
+
}
|
|
362
|
+
throw e;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
336
365
|
var SCHEMA_VERSION, SCHEMA_SQL;
|
|
337
366
|
var init_db = __esm({
|
|
338
367
|
"src/core/db.ts"() {
|
|
339
368
|
"use strict";
|
|
340
|
-
SCHEMA_VERSION =
|
|
369
|
+
SCHEMA_VERSION = 6;
|
|
341
370
|
SCHEMA_SQL = `
|
|
342
371
|
-- Memory entries
|
|
343
372
|
CREATE TABLE IF NOT EXISTS memories (
|
|
@@ -355,6 +384,7 @@ CREATE TABLE IF NOT EXISTS memories (
|
|
|
355
384
|
source TEXT,
|
|
356
385
|
agent_id TEXT NOT NULL DEFAULT 'default',
|
|
357
386
|
hash TEXT,
|
|
387
|
+
emotion_tag TEXT,
|
|
358
388
|
UNIQUE(hash, agent_id)
|
|
359
389
|
);
|
|
360
390
|
|
|
@@ -934,8 +964,8 @@ function createMemory(db, input) {
|
|
|
934
964
|
const timestamp = now();
|
|
935
965
|
db.prepare(
|
|
936
966
|
`INSERT INTO memories (id, content, type, priority, emotion_val, vitality, stability,
|
|
937
|
-
access_count, created_at, updated_at, source, agent_id, hash)
|
|
938
|
-
VALUES (?, ?, ?, ?, ?, 1.0, ?, 0, ?, ?, ?, ?, ?)`
|
|
967
|
+
access_count, created_at, updated_at, source, agent_id, hash, emotion_tag)
|
|
968
|
+
VALUES (?, ?, ?, ?, ?, 1.0, ?, 0, ?, ?, ?, ?, ?, ?)`
|
|
939
969
|
).run(
|
|
940
970
|
id,
|
|
941
971
|
input.content,
|
|
@@ -947,7 +977,8 @@ function createMemory(db, input) {
|
|
|
947
977
|
timestamp,
|
|
948
978
|
input.source ?? null,
|
|
949
979
|
agentId,
|
|
950
|
-
hash2
|
|
980
|
+
hash2,
|
|
981
|
+
input.emotion_tag ?? null
|
|
951
982
|
);
|
|
952
983
|
db.prepare("INSERT INTO memories_fts (id, content) VALUES (?, ?)").run(id, tokenizeForIndex(input.content));
|
|
953
984
|
markEmbeddingDirtyIfNeeded(db, id, hash2, resolveEmbeddingProviderId(input.embedding_provider_id));
|
|
@@ -991,6 +1022,10 @@ function updateMemory(db, id, input) {
|
|
|
991
1022
|
fields.push("source = ?");
|
|
992
1023
|
values.push(input.source);
|
|
993
1024
|
}
|
|
1025
|
+
if (input.emotion_tag !== void 0) {
|
|
1026
|
+
fields.push("emotion_tag = ?");
|
|
1027
|
+
values.push(input.emotion_tag);
|
|
1028
|
+
}
|
|
994
1029
|
fields.push("updated_at = ?");
|
|
995
1030
|
values.push(now());
|
|
996
1031
|
values.push(id);
|
|
@@ -1032,6 +1067,10 @@ function listMemories(db, opts) {
|
|
|
1032
1067
|
conditions.push("vitality >= ?");
|
|
1033
1068
|
params.push(opts.min_vitality);
|
|
1034
1069
|
}
|
|
1070
|
+
if (opts?.emotion_tag) {
|
|
1071
|
+
conditions.push("emotion_tag = ?");
|
|
1072
|
+
params.push(opts.emotion_tag);
|
|
1073
|
+
}
|
|
1035
1074
|
const where = conditions.length ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
1036
1075
|
const limit = opts?.limit ?? 100;
|
|
1037
1076
|
const offset = opts?.offset ?? 0;
|
|
@@ -14901,8 +14940,68 @@ function getPathsByPrefix(db, prefix, agent_id = "default") {
|
|
|
14901
14940
|
|
|
14902
14941
|
// src/sleep/boot.ts
|
|
14903
14942
|
init_memory();
|
|
14943
|
+
function formatRelativeDate(isoDate) {
|
|
14944
|
+
const diffMs = Date.now() - new Date(isoDate).getTime();
|
|
14945
|
+
const diffDays = Math.floor(diffMs / 864e5);
|
|
14946
|
+
if (diffDays <= 0) return "\u4ECA\u5929";
|
|
14947
|
+
if (diffDays === 1) return "\u6628\u5929";
|
|
14948
|
+
if (diffDays <= 7) return `${diffDays}\u5929\u524D`;
|
|
14949
|
+
return isoDate.slice(0, 10);
|
|
14950
|
+
}
|
|
14951
|
+
function loadWarmBootLayers(db, agentId) {
|
|
14952
|
+
const identity = listMemories(db, { agent_id: agentId, type: "identity", limit: 50 });
|
|
14953
|
+
const emotion = listMemories(db, { agent_id: agentId, type: "emotion", limit: 5 });
|
|
14954
|
+
const event = listMemories(db, { agent_id: agentId, type: "event", limit: 7 });
|
|
14955
|
+
const knowledge = listMemories(db, {
|
|
14956
|
+
agent_id: agentId,
|
|
14957
|
+
type: "knowledge",
|
|
14958
|
+
min_vitality: 0.5,
|
|
14959
|
+
limit: 10
|
|
14960
|
+
});
|
|
14961
|
+
return { identity, emotion, event, knowledge };
|
|
14962
|
+
}
|
|
14963
|
+
function formatNarrativeBoot(layers, agentName) {
|
|
14964
|
+
const lines = [];
|
|
14965
|
+
lines.push(`# ${agentName}\u7684\u56DE\u5FC6`);
|
|
14966
|
+
lines.push("");
|
|
14967
|
+
if (layers.identity.length > 0) {
|
|
14968
|
+
lines.push("## \u6211\u662F\u8C01");
|
|
14969
|
+
for (const mem of layers.identity) {
|
|
14970
|
+
lines.push(`- ${mem.content.split("\n")[0].slice(0, 200)}`);
|
|
14971
|
+
}
|
|
14972
|
+
lines.push("");
|
|
14973
|
+
}
|
|
14974
|
+
if (layers.emotion.length > 0) {
|
|
14975
|
+
lines.push("## \u6700\u8FD1\u7684\u5FC3\u60C5");
|
|
14976
|
+
for (const mem of layers.emotion) {
|
|
14977
|
+
const tag = mem.emotion_tag;
|
|
14978
|
+
const time3 = formatRelativeDate(mem.updated_at);
|
|
14979
|
+
const tagStr = tag ? `${tag}, ${time3}` : time3;
|
|
14980
|
+
lines.push(`- ${mem.content.split("\n")[0].slice(0, 200)} (${tagStr})`);
|
|
14981
|
+
}
|
|
14982
|
+
lines.push("");
|
|
14983
|
+
}
|
|
14984
|
+
if (layers.event.length > 0) {
|
|
14985
|
+
lines.push("## \u6700\u8FD1\u53D1\u751F\u7684\u4E8B");
|
|
14986
|
+
for (const mem of layers.event) {
|
|
14987
|
+
const time3 = formatRelativeDate(mem.updated_at);
|
|
14988
|
+
lines.push(`- ${mem.content.split("\n")[0].slice(0, 200)} (${time3})`);
|
|
14989
|
+
}
|
|
14990
|
+
lines.push("");
|
|
14991
|
+
}
|
|
14992
|
+
if (layers.knowledge.length > 0) {
|
|
14993
|
+
lines.push("## \u8FD8\u8BB0\u5F97\u7684\u77E5\u8BC6");
|
|
14994
|
+
for (const mem of layers.knowledge) {
|
|
14995
|
+
lines.push(`- ${mem.content.split("\n")[0].slice(0, 200)}`);
|
|
14996
|
+
}
|
|
14997
|
+
lines.push("");
|
|
14998
|
+
}
|
|
14999
|
+
return lines.join("\n");
|
|
15000
|
+
}
|
|
14904
15001
|
function boot(db, opts) {
|
|
14905
15002
|
const agentId = opts?.agent_id ?? "default";
|
|
15003
|
+
const format = opts?.format ?? "json";
|
|
15004
|
+
const agentName = opts?.agent_name ?? "Agent";
|
|
14906
15005
|
const corePaths = opts?.corePaths ?? [
|
|
14907
15006
|
"core://agent",
|
|
14908
15007
|
"core://user",
|
|
@@ -14946,10 +15045,16 @@ function boot(db, opts) {
|
|
|
14946
15045
|
}
|
|
14947
15046
|
}
|
|
14948
15047
|
}
|
|
14949
|
-
|
|
15048
|
+
const result = {
|
|
14950
15049
|
identityMemories: [...memories.values()],
|
|
14951
15050
|
bootPaths
|
|
14952
15051
|
};
|
|
15052
|
+
if (format === "narrative") {
|
|
15053
|
+
const layers = loadWarmBootLayers(db, agentId);
|
|
15054
|
+
result.layers = layers;
|
|
15055
|
+
result.narrative = formatNarrativeBoot(layers, agentName);
|
|
15056
|
+
}
|
|
15057
|
+
return result;
|
|
14953
15058
|
}
|
|
14954
15059
|
|
|
14955
15060
|
// src/sleep/sync.ts
|
|
@@ -15436,9 +15541,11 @@ function fourCriterionGate(input) {
|
|
|
15436
15541
|
const content = input.content.trim();
|
|
15437
15542
|
const failed = [];
|
|
15438
15543
|
const priority = input.priority ?? (input.type === "identity" ? 0 : input.type === "emotion" ? 1 : input.type === "knowledge" ? 2 : 3);
|
|
15439
|
-
const
|
|
15440
|
-
const
|
|
15441
|
-
|
|
15544
|
+
const cjkCount = (content.match(/[\u4e00-\u9fff\u3400-\u4dbf]/g) ?? []).length;
|
|
15545
|
+
const effectiveLength = content.length + cjkCount * 2;
|
|
15546
|
+
const minLength = priority <= 1 ? 4 : 20;
|
|
15547
|
+
const specificity = effectiveLength >= minLength ? Math.min(1, effectiveLength / 50) : 0;
|
|
15548
|
+
if (specificity === 0) failed.push(`specificity (too short: effective ${effectiveLength} < ${minLength} chars)`);
|
|
15442
15549
|
const tokens = tokenize(content);
|
|
15443
15550
|
const novelty = tokens.length >= 1 ? Math.min(1, tokens.length / 5) : 0;
|
|
15444
15551
|
if (novelty === 0) failed.push("novelty (no meaningful tokens after filtering)");
|
|
@@ -15550,7 +15657,8 @@ async function syncOne(db, input) {
|
|
|
15550
15657
|
agent_id: input.agent_id,
|
|
15551
15658
|
uri: input.uri,
|
|
15552
15659
|
provider: input.provider,
|
|
15553
|
-
conservative: input.conservative
|
|
15660
|
+
conservative: input.conservative,
|
|
15661
|
+
emotion_tag: input.emotion_tag
|
|
15554
15662
|
};
|
|
15555
15663
|
const guardResult = await guard(db, memInput);
|
|
15556
15664
|
switch (guardResult.action) {
|
|
@@ -15614,6 +15722,7 @@ function extractIngestItems(text, source) {
|
|
|
15614
15722
|
const bulletItems = block.body.split(/\n+/).map((line) => line.replace(/^[-*]\s*/, "").trim()).filter(Boolean);
|
|
15615
15723
|
const lines = bulletItems.length > 0 ? bulletItems : [block.body.trim()];
|
|
15616
15724
|
for (const line of lines) {
|
|
15725
|
+
if (isIngestNoise(line)) continue;
|
|
15617
15726
|
index += 1;
|
|
15618
15727
|
const uri = type === "identity" ? `core://ingest/${slugify2(block.title)}/${index}` : `${type}://${slugify2(source ?? "ingest")}/${index}`;
|
|
15619
15728
|
items.push({
|
|
@@ -15626,6 +15735,31 @@ function extractIngestItems(text, source) {
|
|
|
15626
15735
|
}
|
|
15627
15736
|
return items;
|
|
15628
15737
|
}
|
|
15738
|
+
var NOISE_PATTERNS = [
|
|
15739
|
+
/HEARTBEAT_OK/i,
|
|
15740
|
+
/安静模式/,
|
|
15741
|
+
/安静待命/,
|
|
15742
|
+
/不打扰/,
|
|
15743
|
+
/无新.{0,4}(delta|变化|事项|进展)/,
|
|
15744
|
+
/无变化/,
|
|
15745
|
+
/无紧急/,
|
|
15746
|
+
/深夜时段/,
|
|
15747
|
+
/继续安静/,
|
|
15748
|
+
/openclaw (status|gateway status|security audit|update status)/i,
|
|
15749
|
+
/session_status/,
|
|
15750
|
+
/危险区协议/,
|
|
15751
|
+
/没有紧急/,
|
|
15752
|
+
/没有新增状态变化/,
|
|
15753
|
+
/仍为.*critical/,
|
|
15754
|
+
/基线(未变|不变|仍)/,
|
|
15755
|
+
/PR\s*#\d+\s*(无变化|状态无变化)/,
|
|
15756
|
+
/距上次心跳/,
|
|
15757
|
+
/轻量复查/,
|
|
15758
|
+
/cron 会话.*\d+k/
|
|
15759
|
+
];
|
|
15760
|
+
function isIngestNoise(content) {
|
|
15761
|
+
return NOISE_PATTERNS.some((pattern) => pattern.test(content));
|
|
15762
|
+
}
|
|
15629
15763
|
async function ingestText(db, options) {
|
|
15630
15764
|
const extracted = extractIngestItems(options.text, options.source);
|
|
15631
15765
|
const dryRun = options.dryRun ?? false;
|
|
@@ -15830,21 +15964,26 @@ async function rememberMemory(db, input) {
|
|
|
15830
15964
|
source: input.source,
|
|
15831
15965
|
agent_id: input.agent_id,
|
|
15832
15966
|
provider: input.provider,
|
|
15833
|
-
conservative: input.conservative
|
|
15967
|
+
conservative: input.conservative,
|
|
15968
|
+
emotion_tag: input.emotion_tag
|
|
15834
15969
|
});
|
|
15835
15970
|
}
|
|
15836
15971
|
|
|
15837
15972
|
// src/app/recall.ts
|
|
15838
15973
|
async function recallMemory(db, input) {
|
|
15839
|
-
|
|
15974
|
+
const result = await recallMemories(db, input.query, {
|
|
15840
15975
|
agent_id: input.agent_id,
|
|
15841
|
-
limit: input.limit,
|
|
15976
|
+
limit: input.emotion_tag ? (input.limit ?? 10) * 3 : input.limit,
|
|
15842
15977
|
min_vitality: input.min_vitality,
|
|
15843
15978
|
lexicalLimit: input.lexicalLimit,
|
|
15844
15979
|
vectorLimit: input.vectorLimit,
|
|
15845
15980
|
provider: input.provider,
|
|
15846
15981
|
recordAccess: input.recordAccess
|
|
15847
15982
|
});
|
|
15983
|
+
if (input.emotion_tag) {
|
|
15984
|
+
result.results = result.results.filter((r) => r.memory.emotion_tag === input.emotion_tag).slice(0, input.limit ?? 10);
|
|
15985
|
+
}
|
|
15986
|
+
return result;
|
|
15848
15987
|
}
|
|
15849
15988
|
|
|
15850
15989
|
// src/app/surface.ts
|
|
@@ -16093,7 +16232,7 @@ async function surfaceMemories(db, input) {
|
|
|
16093
16232
|
signals.set(memory.id, { memory });
|
|
16094
16233
|
}
|
|
16095
16234
|
}
|
|
16096
|
-
const results = [...signals.values()].map((signal) => signal.memory).filter((memory) => memory.vitality >= minVitality).filter((memory) => input.types?.length ? input.types.includes(memory.type) : true).map((memory) => {
|
|
16235
|
+
const results = [...signals.values()].map((signal) => signal.memory).filter((memory) => memory.vitality >= minVitality).filter((memory) => input.types?.length ? input.types.includes(memory.type) : true).filter((memory) => input.emotion_tag ? memory.emotion_tag === input.emotion_tag : true).map((memory) => {
|
|
16097
16236
|
const signal = signals.get(memory.id) ?? { memory };
|
|
16098
16237
|
const memoryTokens = new Set(tokenize(memory.content));
|
|
16099
16238
|
const lexicalOverlap = overlapScore2(memoryTokens, queryTokens);
|
|
@@ -16204,9 +16343,9 @@ function getDecayedMemories(db, threshold = 0.05, opts) {
|
|
|
16204
16343
|
const agentId = opts?.agent_id;
|
|
16205
16344
|
return db.prepare(
|
|
16206
16345
|
agentId ? `SELECT id, content, vitality, priority FROM memories
|
|
16207
|
-
WHERE vitality < ? AND priority >=
|
|
16346
|
+
WHERE vitality < ? AND priority >= 2 AND agent_id = ?
|
|
16208
16347
|
ORDER BY vitality ASC` : `SELECT id, content, vitality, priority FROM memories
|
|
16209
|
-
WHERE vitality < ? AND priority >=
|
|
16348
|
+
WHERE vitality < ? AND priority >= 2
|
|
16210
16349
|
ORDER BY vitality ASC`
|
|
16211
16350
|
).all(...agentId ? [threshold, agentId] : [threshold]);
|
|
16212
16351
|
}
|
|
@@ -16304,7 +16443,8 @@ function rankEvictionCandidates(db, opts) {
|
|
|
16304
16443
|
}
|
|
16305
16444
|
function runGovern(db, opts) {
|
|
16306
16445
|
const agentId = opts?.agent_id;
|
|
16307
|
-
const
|
|
16446
|
+
const envMax = Number.parseInt(process.env.AGENT_MEMORY_MAX_MEMORIES ?? "", 10);
|
|
16447
|
+
const maxMemories = opts?.maxMemories ?? (Number.isFinite(envMax) && envMax > 0 ? envMax : 200);
|
|
16308
16448
|
let orphanPaths = 0;
|
|
16309
16449
|
let emptyMemories = 0;
|
|
16310
16450
|
let evicted = 0;
|
|
@@ -16763,10 +16903,11 @@ function createMcpServer(dbPath, agentId) {
|
|
|
16763
16903
|
uri: external_exports.string().optional().describe("URI path (e.g. core://user/name, emotion://2026-02-20/love)"),
|
|
16764
16904
|
emotion_val: external_exports.number().min(-1).max(1).default(0).describe("Emotional valence (-1 negative to +1 positive)"),
|
|
16765
16905
|
source: external_exports.string().optional().describe("Source annotation (e.g. session ID, date)"),
|
|
16766
|
-
agent_id: external_exports.string().optional().describe("Override agent scope (defaults to current agent)")
|
|
16906
|
+
agent_id: external_exports.string().optional().describe("Override agent scope (defaults to current agent)"),
|
|
16907
|
+
emotion_tag: external_exports.string().optional().describe("Emotion label for emotion-type memories (e.g. \u5B89\u5FC3, \u5F00\u5FC3, \u62C5\u5FC3)")
|
|
16767
16908
|
},
|
|
16768
|
-
async ({ content, type, uri, emotion_val, source, agent_id }) => {
|
|
16769
|
-
const result = await rememberMemory(db, { content, type, uri, emotion_val, source, agent_id: agent_id ?? aid });
|
|
16909
|
+
async ({ content, type, uri, emotion_val, source, agent_id, emotion_tag }) => {
|
|
16910
|
+
const result = await rememberMemory(db, { content, type, uri, emotion_val, source, agent_id: agent_id ?? aid, emotion_tag });
|
|
16770
16911
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
16771
16912
|
}
|
|
16772
16913
|
);
|
|
@@ -16776,10 +16917,11 @@ function createMcpServer(dbPath, agentId) {
|
|
|
16776
16917
|
{
|
|
16777
16918
|
query: external_exports.string().describe("Search query (natural language)"),
|
|
16778
16919
|
limit: external_exports.number().default(10).describe("Max results to return"),
|
|
16779
|
-
agent_id: external_exports.string().optional().describe("Override agent scope (defaults to current agent)")
|
|
16920
|
+
agent_id: external_exports.string().optional().describe("Override agent scope (defaults to current agent)"),
|
|
16921
|
+
emotion_tag: external_exports.string().optional().describe("Filter results by emotion tag (e.g. \u5B89\u5FC3, \u5F00\u5FC3)")
|
|
16780
16922
|
},
|
|
16781
|
-
async ({ query, limit, agent_id }) => {
|
|
16782
|
-
const result = await recallMemory(db, { query, limit, agent_id: agent_id ?? aid });
|
|
16923
|
+
async ({ query, limit, agent_id, emotion_tag }) => {
|
|
16924
|
+
const result = await recallMemory(db, { query, limit, agent_id: agent_id ?? aid, emotion_tag });
|
|
16783
16925
|
return { content: [{ type: "text", text: JSON.stringify(formatRecallPayload(result), null, 2) }] };
|
|
16784
16926
|
}
|
|
16785
16927
|
);
|
|
@@ -16827,19 +16969,20 @@ function createMcpServer(dbPath, agentId) {
|
|
|
16827
16969
|
"boot",
|
|
16828
16970
|
"Load startup memories. Default output is narrative markdown; pass format=json for legacy output.",
|
|
16829
16971
|
{
|
|
16830
|
-
format: external_exports.enum(["narrative", "json"]).default("narrative").optional()
|
|
16972
|
+
format: external_exports.enum(["narrative", "json"]).default("narrative").optional(),
|
|
16973
|
+
agent_name: external_exports.string().optional().describe("Agent name for narrative header (default: Agent)")
|
|
16831
16974
|
},
|
|
16832
|
-
async ({ format }) => {
|
|
16975
|
+
async ({ format, agent_name }) => {
|
|
16833
16976
|
const outputFormat = format ?? "narrative";
|
|
16834
|
-
const
|
|
16977
|
+
const result = boot(db, { agent_id: aid, format: outputFormat, agent_name: agent_name ?? void 0 });
|
|
16835
16978
|
if (outputFormat === "json") {
|
|
16836
16979
|
return {
|
|
16837
16980
|
content: [{
|
|
16838
16981
|
type: "text",
|
|
16839
16982
|
text: JSON.stringify({
|
|
16840
|
-
count:
|
|
16841
|
-
bootPaths:
|
|
16842
|
-
memories:
|
|
16983
|
+
count: result.identityMemories.length,
|
|
16984
|
+
bootPaths: result.bootPaths,
|
|
16985
|
+
memories: result.identityMemories.map((memory) => ({
|
|
16843
16986
|
id: memory.id,
|
|
16844
16987
|
content: memory.content,
|
|
16845
16988
|
type: memory.type,
|
|
@@ -16849,12 +16992,15 @@ function createMcpServer(dbPath, agentId) {
|
|
|
16849
16992
|
}]
|
|
16850
16993
|
};
|
|
16851
16994
|
}
|
|
16995
|
+
if (result.narrative) {
|
|
16996
|
+
return { content: [{ type: "text", text: result.narrative }] };
|
|
16997
|
+
}
|
|
16852
16998
|
const identity = listMemories(db, { agent_id: aid, type: "identity", limit: 12 });
|
|
16853
16999
|
const emotion = listMemories(db, { agent_id: aid, type: "emotion", min_vitality: 0.1, limit: 12 }).sort((a, b) => b.vitality - a.vitality);
|
|
16854
17000
|
const knowledge = listMemories(db, { agent_id: aid, type: "knowledge", min_vitality: 0.1, limit: 16 }).sort((a, b) => b.vitality - a.vitality);
|
|
16855
17001
|
const event = listMemories(db, { agent_id: aid, type: "event", min_vitality: 0, limit: 24 }).sort((a, b) => b.vitality - a.vitality);
|
|
16856
17002
|
const stats = countMemories(db, aid);
|
|
16857
|
-
return { content: [{ type: "text", text: formatWarmBootNarrative(identity.length > 0 ? identity :
|
|
17003
|
+
return { content: [{ type: "text", text: formatWarmBootNarrative(identity.length > 0 ? identity : result.identityMemories, emotion, knowledge, event, stats) }] };
|
|
16858
17004
|
}
|
|
16859
17005
|
);
|
|
16860
17006
|
server.tool(
|