mcp-agents-memory 0.6.2 → 0.8.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/README.md +2 -0
- package/build/index.js +95 -49
- package/build/migrations/016_agent_curator.js +25987 -0
- package/build/migrations/017_drop_trust_weight.js +25985 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -102,6 +102,8 @@ Claude Desktop / Claude Code / any MCP-aware client:
|
|
|
102
102
|
|
|
103
103
|
`AGENT_PLATFORM` is recorded as the Curator's harness identity on every memory_add call. The Curator's model is captured per-call (defaulting to the Producer's author_model) — set explicitly via the curator_model argument when an orchestrator saves memories on behalf of a different model (e.g. delegating to a subagent). This avoids the staleness that env-static model values would introduce when /model swaps mid-session.
|
|
104
104
|
|
|
105
|
+
`agent_key` (optional): Agent persona key for multi-persona harnesses (OpenClaw, Hermes, Opencode). Single-persona setups can ignore — `AGENT_KEY` env is the default. Applies to `memory_add`, `memory_save_skill`, and `memory_curator_run`.
|
|
106
|
+
|
|
105
107
|
### Cross-machine memory
|
|
106
108
|
|
|
107
109
|
On a second computer, run `npm i -g mcp-agents-memory` and `mcp-agents-memory setup` pointing to the **same** `DATABASE_URL`. Memory shares automatically — the database is the source of truth and the MCP server is stateless.
|
package/build/index.js
CHANGED
|
@@ -116026,22 +116026,21 @@ ${JSON.stringify(toAudit)}`,
|
|
|
116026
116026
|
}
|
|
116027
116027
|
var MODEL_CACHE = /* @__PURE__ */ new Map();
|
|
116028
116028
|
var PLATFORM_CACHE = /* @__PURE__ */ new Map();
|
|
116029
|
-
var DEFAULT_TRUST_WEIGHT = 0.8;
|
|
116030
116029
|
async function resolvePlatform(name) {
|
|
116031
116030
|
if (!name) return null;
|
|
116032
116031
|
const key = name.toLowerCase();
|
|
116033
116032
|
if (PLATFORM_CACHE.has(key)) return PLATFORM_CACHE.get(key);
|
|
116034
|
-
const sel = await db.query("SELECT id, name
|
|
116033
|
+
const sel = await db.query("SELECT id, name FROM platforms WHERE LOWER(name) = $1 LIMIT 1", [key]);
|
|
116035
116034
|
if (sel.rows.length > 0) {
|
|
116036
|
-
const r2 = { id: sel.rows[0].id, name: sel.rows[0].name
|
|
116035
|
+
const r2 = { id: sel.rows[0].id, name: sel.rows[0].name };
|
|
116037
116036
|
PLATFORM_CACHE.set(key, r2);
|
|
116038
116037
|
return r2;
|
|
116039
116038
|
}
|
|
116040
116039
|
const ins = await db.query(
|
|
116041
|
-
"INSERT INTO platforms (name
|
|
116040
|
+
"INSERT INTO platforms (name) VALUES ($1) ON CONFLICT (name) DO UPDATE SET name = EXCLUDED.name RETURNING id, name",
|
|
116042
116041
|
[name]
|
|
116043
116042
|
);
|
|
116044
|
-
const r = { id: ins.rows[0].id, name: ins.rows[0].name
|
|
116043
|
+
const r = { id: ins.rows[0].id, name: ins.rows[0].name };
|
|
116045
116044
|
PLATFORM_CACHE.set(key, r);
|
|
116046
116045
|
console.error(`\u2728 [Librarian] Auto-registered platform "${name}"`);
|
|
116047
116046
|
return r;
|
|
@@ -116052,34 +116051,46 @@ async function resolveModel(name) {
|
|
|
116052
116051
|
if (MODEL_CACHE.has(key)) return MODEL_CACHE.get(key);
|
|
116053
116052
|
try {
|
|
116054
116053
|
const res = await db.query(
|
|
116055
|
-
`SELECT id, model_name
|
|
116054
|
+
`SELECT id, model_name
|
|
116056
116055
|
FROM models
|
|
116057
116056
|
WHERE LOWER(model_name) = $1
|
|
116058
116057
|
OR LOWER(metadata->>'alias') = $1
|
|
116059
116058
|
LIMIT 1`,
|
|
116060
116059
|
[key]
|
|
116061
116060
|
);
|
|
116062
|
-
if (res.rows.length
|
|
116063
|
-
|
|
116061
|
+
if (res.rows.length > 0) {
|
|
116062
|
+
const resolved2 = {
|
|
116063
|
+
id: res.rows[0].id,
|
|
116064
|
+
model_name: res.rows[0].model_name
|
|
116065
|
+
};
|
|
116066
|
+
MODEL_CACHE.set(key, resolved2);
|
|
116067
|
+
return resolved2;
|
|
116068
|
+
}
|
|
116069
|
+
const provider = inferProvider(name);
|
|
116070
|
+
if (!provider) {
|
|
116071
|
+
console.error(`\u26A0\uFE0F [Librarian] Unknown model "${name}" \u2014 provider not inferable, author_model_id=NULL`);
|
|
116064
116072
|
MODEL_CACHE.set(key, null);
|
|
116065
116073
|
return null;
|
|
116066
116074
|
}
|
|
116075
|
+
const ins = await db.query(
|
|
116076
|
+
`INSERT INTO models (provider, model_name, metadata)
|
|
116077
|
+
VALUES ($1, $2, '{}'::jsonb)
|
|
116078
|
+
ON CONFLICT (model_name) DO UPDATE SET model_name = EXCLUDED.model_name
|
|
116079
|
+
RETURNING id, model_name`,
|
|
116080
|
+
[provider, name]
|
|
116081
|
+
);
|
|
116067
116082
|
const resolved = {
|
|
116068
|
-
id:
|
|
116069
|
-
|
|
116070
|
-
model_name: res.rows[0].model_name
|
|
116083
|
+
id: ins.rows[0].id,
|
|
116084
|
+
model_name: ins.rows[0].model_name
|
|
116071
116085
|
};
|
|
116072
116086
|
MODEL_CACHE.set(key, resolved);
|
|
116087
|
+
console.error(`\u2728 [Librarian] Auto-registered model "${name}" (provider=${provider})`);
|
|
116073
116088
|
return resolved;
|
|
116074
116089
|
} catch (err) {
|
|
116075
116090
|
console.error(`\u274C [Librarian] resolveModel failed for "${name}":`, err);
|
|
116076
116091
|
return null;
|
|
116077
116092
|
}
|
|
116078
116093
|
}
|
|
116079
|
-
function computeEffectiveConfidence(confidence, trustWeight) {
|
|
116080
|
-
const raw = confidence / 10 * trustWeight;
|
|
116081
|
-
return Math.round(raw * 100) / 100;
|
|
116082
|
-
}
|
|
116083
116094
|
async function resolveContradiction(newFact, subjectId, existingEmbedding) {
|
|
116084
116095
|
try {
|
|
116085
116096
|
const embedding = existingEmbedding || await generateEmbedding(newFact.content);
|
|
@@ -116220,8 +116231,6 @@ async function processBatch(text, subjectId, projectId, rawSource, provenance =
|
|
|
116220
116231
|
}
|
|
116221
116232
|
const resolvedModel = await resolveModel(provenance.author_model);
|
|
116222
116233
|
const resolvedPlatform = await resolvePlatform(provenance.platform);
|
|
116223
|
-
const trustWeight = resolvedModel?.trust_weight ?? DEFAULT_TRUST_WEIGHT;
|
|
116224
|
-
const effectiveConfidence = computeEffectiveConfidence(fact.confidence, trustWeight);
|
|
116225
116234
|
const auditedStatus = auditResult ? tierToStatus(auditResult.validation_tier) : null;
|
|
116226
116235
|
const validationStatus = auditedStatus ?? (fact.importance > 7 ? "pending" : "valid");
|
|
116227
116236
|
const insertRes = await db.query(
|
|
@@ -116229,8 +116238,8 @@ async function processBatch(text, subjectId, projectId, rawSource, provenance =
|
|
|
116229
116238
|
subject_id, project_subject_id, content, fact_type,
|
|
116230
116239
|
confidence, importance, tags, embedding, validation_status,
|
|
116231
116240
|
author_model, platform, session_id,
|
|
116232
|
-
agent_platform, agent_model,
|
|
116233
|
-
author_model_id, platform_id,
|
|
116241
|
+
agent_platform, agent_model, agent_curator_id,
|
|
116242
|
+
author_model_id, platform_id, source
|
|
116234
116243
|
)
|
|
116235
116244
|
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18)
|
|
116236
116245
|
RETURNING id`,
|
|
@@ -116249,9 +116258,9 @@ async function processBatch(text, subjectId, projectId, rawSource, provenance =
|
|
|
116249
116258
|
provenance.session_id,
|
|
116250
116259
|
provenance.agent_platform,
|
|
116251
116260
|
provenance.agent_model,
|
|
116261
|
+
provenance.agent_curator_id ?? null,
|
|
116252
116262
|
resolvedModel?.id ?? null,
|
|
116253
116263
|
resolvedPlatform?.id ?? null,
|
|
116254
|
-
effectiveConfidence,
|
|
116255
116264
|
provenance.source ?? "librarian"
|
|
116256
116265
|
]
|
|
116257
116266
|
);
|
|
@@ -116317,26 +116326,33 @@ var BRANCH_THRESHOLD = 0.7;
|
|
|
116317
116326
|
function singletonArray(value) {
|
|
116318
116327
|
return typeof value === "number" ? [value] : [];
|
|
116319
116328
|
}
|
|
116329
|
+
function mergeProjectIntoApplicableTo(base, projectKey) {
|
|
116330
|
+
if (!projectKey) return base;
|
|
116331
|
+
if (Array.isArray(base.projects)) return base;
|
|
116332
|
+
return { ...base, projects: [projectKey] };
|
|
116333
|
+
}
|
|
116320
116334
|
function getPersistedSkillFields(candidate, audit) {
|
|
116321
116335
|
if (!audit) {
|
|
116336
|
+
const applicable = mergeProjectIntoApplicableTo({}, candidate.project_key);
|
|
116322
116337
|
return {
|
|
116323
116338
|
content: candidate.content,
|
|
116324
116339
|
sources: JSON.stringify([]),
|
|
116325
116340
|
validationTier: "unvalidated",
|
|
116326
|
-
applicableTo: JSON.stringify(
|
|
116341
|
+
applicableTo: JSON.stringify(applicable),
|
|
116327
116342
|
auditMetadata: {}
|
|
116328
116343
|
};
|
|
116329
116344
|
}
|
|
116345
|
+
const merged = mergeProjectIntoApplicableTo(audit.applicable_to ?? {}, candidate.project_key);
|
|
116330
116346
|
return {
|
|
116331
116347
|
content: audit.reconciled_content,
|
|
116332
116348
|
sources: JSON.stringify(audit.sources),
|
|
116333
116349
|
validationTier: audit.validation_tier,
|
|
116334
|
-
applicableTo: JSON.stringify(
|
|
116350
|
+
applicableTo: JSON.stringify(merged),
|
|
116335
116351
|
auditMetadata: {
|
|
116336
116352
|
validation_tier: audit.validation_tier,
|
|
116337
116353
|
audit_reasoning: audit.audit_reasoning,
|
|
116338
116354
|
sources: audit.sources,
|
|
116339
|
-
applicable_to:
|
|
116355
|
+
applicable_to: merged
|
|
116340
116356
|
}
|
|
116341
116357
|
};
|
|
116342
116358
|
}
|
|
@@ -116374,11 +116390,14 @@ async function getInjectableSkills(ctx) {
|
|
|
116374
116390
|
AND
|
|
116375
116391
|
($2::text IS NULL OR NOT (applicable_to ? 'platforms')
|
|
116376
116392
|
OR applicable_to->'platforms' @> to_jsonb($2::text))
|
|
116393
|
+
AND
|
|
116394
|
+
($3::text IS NULL OR NOT (applicable_to ? 'projects')
|
|
116395
|
+
OR applicable_to->'projects' @> to_jsonb($3::text))
|
|
116377
116396
|
)
|
|
116378
116397
|
)
|
|
116379
116398
|
ORDER BY use_count DESC, last_used_at DESC NULLS LAST, created_at DESC
|
|
116380
|
-
LIMIT $
|
|
116381
|
-
[ctx.author_model ?? null, ctx.platform ?? null, limit2]
|
|
116399
|
+
LIMIT $4`,
|
|
116400
|
+
[ctx.author_model ?? null, ctx.platform ?? null, ctx.project_key ?? null, limit2]
|
|
116382
116401
|
);
|
|
116383
116402
|
return res.rows.map((row) => ({
|
|
116384
116403
|
id: Number(row.id),
|
|
@@ -116398,7 +116417,7 @@ async function recordSkillExposure(skillIds) {
|
|
|
116398
116417
|
[skillIds]
|
|
116399
116418
|
);
|
|
116400
116419
|
}
|
|
116401
|
-
async function updateOrCreateSkill(candidate, audit) {
|
|
116420
|
+
async function updateOrCreateSkill(candidate, audit, agentCuratorId) {
|
|
116402
116421
|
const persisted = getPersistedSkillFields(candidate, audit);
|
|
116403
116422
|
const embedding = await generateEmbedding(`${candidate.title}
|
|
116404
116423
|
|
|
@@ -116418,16 +116437,23 @@ ${persisted.content}`);
|
|
|
116418
116437
|
await client2.query(
|
|
116419
116438
|
`UPDATE skills
|
|
116420
116439
|
SET use_count = use_count + 1,
|
|
116421
|
-
last_used_at = NOW()
|
|
116440
|
+
last_used_at = NOW(),
|
|
116441
|
+
applicable_to = CASE
|
|
116442
|
+
WHEN $2::text IS NULL THEN applicable_to
|
|
116443
|
+
WHEN NOT (applicable_to ? 'projects') THEN applicable_to
|
|
116444
|
+
WHEN applicable_to->'projects' @> to_jsonb($2::text) THEN applicable_to
|
|
116445
|
+
ELSE jsonb_set(applicable_to, '{projects}',
|
|
116446
|
+
applicable_to->'projects' || to_jsonb($2::text))
|
|
116447
|
+
END
|
|
116422
116448
|
WHERE id = $1`,
|
|
116423
|
-
[match.id]
|
|
116449
|
+
[match.id, candidate.project_key ?? null]
|
|
116424
116450
|
);
|
|
116425
116451
|
await client2.query(
|
|
116426
116452
|
`INSERT INTO skill_changelog (
|
|
116427
116453
|
skill_id, change_type, content_diff, source_memory_ids,
|
|
116428
|
-
author_model_id, platform_id, metadata
|
|
116454
|
+
author_model_id, platform_id, metadata, agent_curator_id
|
|
116429
116455
|
)
|
|
116430
|
-
VALUES ($1, 'append', $2, $3, $4, $5, $6)`,
|
|
116456
|
+
VALUES ($1, 'append', $2, $3, $4, $5, $6, $7)`,
|
|
116431
116457
|
[
|
|
116432
116458
|
match.id,
|
|
116433
116459
|
persisted.content,
|
|
@@ -116439,7 +116465,8 @@ ${persisted.content}`);
|
|
|
116439
116465
|
matched_skill_id: match.id,
|
|
116440
116466
|
similarity,
|
|
116441
116467
|
audit: persisted.auditMetadata
|
|
116442
|
-
})
|
|
116468
|
+
}),
|
|
116469
|
+
agentCuratorId ?? null
|
|
116443
116470
|
]
|
|
116444
116471
|
);
|
|
116445
116472
|
await client2.query("COMMIT");
|
|
@@ -116481,9 +116508,9 @@ ${persisted.content}`);
|
|
|
116481
116508
|
await client2.query(
|
|
116482
116509
|
`INSERT INTO skill_changelog (
|
|
116483
116510
|
skill_id, change_type, content_diff, source_memory_ids,
|
|
116484
|
-
author_model_id, platform_id, metadata
|
|
116511
|
+
author_model_id, platform_id, metadata, agent_curator_id
|
|
116485
116512
|
)
|
|
116486
|
-
VALUES ($1, 'branched', $2, $3, $4, $5, $6)`,
|
|
116513
|
+
VALUES ($1, 'branched', $2, $3, $4, $5, $6, $7)`,
|
|
116487
116514
|
[
|
|
116488
116515
|
skillId2,
|
|
116489
116516
|
persisted.content,
|
|
@@ -116494,7 +116521,8 @@ ${persisted.content}`);
|
|
|
116494
116521
|
branched_from_skill_id: match.id,
|
|
116495
116522
|
similarity,
|
|
116496
116523
|
audit: persisted.auditMetadata
|
|
116497
|
-
})
|
|
116524
|
+
}),
|
|
116525
|
+
agentCuratorId ?? null
|
|
116498
116526
|
]
|
|
116499
116527
|
);
|
|
116500
116528
|
await client2.query("COMMIT");
|
|
@@ -116528,9 +116556,9 @@ ${persisted.content}`);
|
|
|
116528
116556
|
await client2.query(
|
|
116529
116557
|
`INSERT INTO skill_changelog (
|
|
116530
116558
|
skill_id, change_type, content_diff, source_memory_ids,
|
|
116531
|
-
author_model_id, platform_id, metadata
|
|
116559
|
+
author_model_id, platform_id, metadata, agent_curator_id
|
|
116532
116560
|
)
|
|
116533
|
-
VALUES ($1, 'created', $2, $3, $4, $5, $6)`,
|
|
116561
|
+
VALUES ($1, 'created', $2, $3, $4, $5, $6, $7)`,
|
|
116534
116562
|
[
|
|
116535
116563
|
skillId,
|
|
116536
116564
|
persisted.content,
|
|
@@ -116541,7 +116569,8 @@ ${persisted.content}`);
|
|
|
116541
116569
|
matched_skill_id: match?.id ?? null,
|
|
116542
116570
|
similarity,
|
|
116543
116571
|
audit: persisted.auditMetadata
|
|
116544
|
-
})
|
|
116572
|
+
}),
|
|
116573
|
+
agentCuratorId ?? null
|
|
116545
116574
|
]
|
|
116546
116575
|
);
|
|
116547
116576
|
await client2.query("COMMIT");
|
|
@@ -116902,7 +116931,10 @@ async function runCurator(options = {}) {
|
|
|
116902
116931
|
content: parsed.content,
|
|
116903
116932
|
source_memory_ids: cluster.member_ids,
|
|
116904
116933
|
author_model: "curator",
|
|
116905
|
-
platform: "system"
|
|
116934
|
+
platform: "system",
|
|
116935
|
+
// v0.8: propagate project scope from cluster context to the skill.
|
|
116936
|
+
// Cross-project clusters (projectKey unset) leave applicable_to.projects unset → match-all.
|
|
116937
|
+
project_key: options.projectKey
|
|
116906
116938
|
};
|
|
116907
116939
|
let audit;
|
|
116908
116940
|
let audited;
|
|
@@ -116924,7 +116956,7 @@ async function runCurator(options = {}) {
|
|
|
116924
116956
|
}
|
|
116925
116957
|
let skillResult = null;
|
|
116926
116958
|
if (!normalized.dryRun) {
|
|
116927
|
-
skillResult = await updateOrCreateSkill(candidate, audited);
|
|
116959
|
+
skillResult = await updateOrCreateSkill(candidate, audited, options.agentCuratorId ?? null);
|
|
116928
116960
|
result.skills_saved++;
|
|
116929
116961
|
}
|
|
116930
116962
|
result.candidates.push({
|
|
@@ -117355,7 +117387,8 @@ function registerTools(server) {
|
|
|
117355
117387
|
inputSchema: {
|
|
117356
117388
|
user_key: external_exports.string().optional().default(process.env.MEMORY_DEFAULT_SUBJECT || "default_user").describe("User subject key."),
|
|
117357
117389
|
author_model: external_exports.string().optional().describe("Caller's author model (for skill filtering)."),
|
|
117358
|
-
platform: external_exports.string().optional().describe("Caller's platform (for skill filtering).")
|
|
117390
|
+
platform: external_exports.string().optional().describe("Caller's platform (for skill filtering)."),
|
|
117391
|
+
project_key: external_exports.string().optional().describe("Active project key. Skills scoped to specific projects only inject when this matches; unscoped skills (applicable_to.projects unset) inject regardless.")
|
|
117359
117392
|
}
|
|
117360
117393
|
},
|
|
117361
117394
|
async (args) => {
|
|
@@ -117456,6 +117489,7 @@ function registerTools(server) {
|
|
|
117456
117489
|
const skills = await getInjectableSkills({
|
|
117457
117490
|
author_model: args.author_model,
|
|
117458
117491
|
platform: args.platform,
|
|
117492
|
+
project_key: args.project_key,
|
|
117459
117493
|
limit: 5
|
|
117460
117494
|
});
|
|
117461
117495
|
if (skills.length > 0) {
|
|
@@ -117511,19 +117545,22 @@ function registerTools(server) {
|
|
|
117511
117545
|
project_key: external_exports.string().optional().describe("Project key if relevant."),
|
|
117512
117546
|
author_model: external_exports.string().optional().describe("Model name or alias (e.g., 'sonnet', 'opus', 'gemini')."),
|
|
117513
117547
|
curator_model: external_exports.string().optional().describe("Curator model override \u2014 the model running memory_add. Defaults to author_model (Producer == Curator solo case)."),
|
|
117548
|
+
agent_key: external_exports.string().optional().describe("Agent persona key (e.g., 'agent_openclaw_reviewer'). Multi-persona harnesses pass this per-call to differentiate personas in calibration data. Defaults to env AGENT_KEY."),
|
|
117514
117549
|
platform: external_exports.string().optional().describe("Platform (e.g., 'antigravity', 'claude-code')."),
|
|
117515
117550
|
session_id: external_exports.string().optional().describe("Unique session identifier.")
|
|
117516
117551
|
}
|
|
117517
117552
|
},
|
|
117518
117553
|
async (args) => {
|
|
117519
117554
|
const agentPlatform = process.env.AGENT_PLATFORM;
|
|
117555
|
+
const agentKeyRaw = args.agent_key ?? process.env.AGENT_KEY ?? null;
|
|
117556
|
+
const agentCuratorId = agentKeyRaw ? await getOrCreateSubject(agentKeyRaw, "agent") : null;
|
|
117520
117557
|
const subjectId = await getOrCreateSubject(args.subject_key, "person");
|
|
117521
117558
|
let projectId = null;
|
|
117522
117559
|
if (args.project_key) {
|
|
117523
117560
|
projectId = await getOrCreateSubject(args.project_key, "project");
|
|
117524
117561
|
}
|
|
117525
|
-
const authorModel = args.author_model ??
|
|
117526
|
-
const curatorModel = args.curator_model ?? args.author_model ??
|
|
117562
|
+
const authorModel = args.author_model ?? void 0;
|
|
117563
|
+
const curatorModel = args.curator_model ?? args.author_model ?? void 0;
|
|
117527
117564
|
const platform = args.platform ?? agentPlatform;
|
|
117528
117565
|
const result = await processBatch(
|
|
117529
117566
|
args.text,
|
|
@@ -117535,6 +117572,7 @@ function registerTools(server) {
|
|
|
117535
117572
|
platform,
|
|
117536
117573
|
agent_platform: agentPlatform,
|
|
117537
117574
|
agent_model: curatorModel,
|
|
117575
|
+
agent_curator_id: agentCuratorId,
|
|
117538
117576
|
session_id: args.session_id
|
|
117539
117577
|
}
|
|
117540
117578
|
);
|
|
@@ -117568,6 +117606,8 @@ function registerTools(server) {
|
|
|
117568
117606
|
source_memory_ids: external_exports.array(external_exports.number()).optional().describe("Memory IDs that produced this skill."),
|
|
117569
117607
|
author_model: external_exports.string().optional().describe("Model name or alias that authored the skill."),
|
|
117570
117608
|
platform: external_exports.string().optional().describe("Platform where the skill was authored."),
|
|
117609
|
+
project_key: external_exports.string().optional().describe("Project subject key. If set, skill is scoped to this project (only injects when memory_startup gets matching project_key). Omit for cross-project skills."),
|
|
117610
|
+
agent_key: external_exports.string().optional().describe("Agent persona key. See memory_add for details."),
|
|
117571
117611
|
audit: external_exports.boolean().optional().default(true).describe("Run Skill Auditor before saving. Default: true.")
|
|
117572
117612
|
}
|
|
117573
117613
|
},
|
|
@@ -117577,10 +117617,13 @@ function registerTools(server) {
|
|
|
117577
117617
|
content: args.content,
|
|
117578
117618
|
source_memory_ids: args.source_memory_ids,
|
|
117579
117619
|
author_model: args.author_model,
|
|
117580
|
-
platform: args.platform
|
|
117620
|
+
platform: args.platform,
|
|
117621
|
+
project_key: args.project_key
|
|
117581
117622
|
};
|
|
117623
|
+
const agentKeyRaw = args.agent_key ?? process.env.AGENT_KEY ?? null;
|
|
117624
|
+
const agentCuratorId = agentKeyRaw ? await getOrCreateSubject(agentKeyRaw, "agent") : null;
|
|
117582
117625
|
const audited = args.audit !== false ? await auditSkill(candidate) : void 0;
|
|
117583
|
-
const result = await updateOrCreateSkill(candidate, audited);
|
|
117626
|
+
const result = await updateOrCreateSkill(candidate, audited, agentCuratorId);
|
|
117584
117627
|
const validationTier = audited?.validation_tier ?? "unvalidated";
|
|
117585
117628
|
const auditReasoning = audited?.audit_reasoning ?? "audit disabled";
|
|
117586
117629
|
const sourcesCount = audited?.sources.length ?? 0;
|
|
@@ -117613,10 +117656,13 @@ function registerTools(server) {
|
|
|
117613
117656
|
min_cluster_size: external_exports.number().optional().describe("Minimum memory count per cluster."),
|
|
117614
117657
|
similarity_threshold: external_exports.number().optional().describe("Minimum cosine similarity for cluster membership."),
|
|
117615
117658
|
min_importance: external_exports.number().optional().describe("Minimum average importance for accepted clusters."),
|
|
117616
|
-
max_clusters: external_exports.number().optional().describe("Maximum clusters to analyze in one run.")
|
|
117659
|
+
max_clusters: external_exports.number().optional().describe("Maximum clusters to analyze in one run."),
|
|
117660
|
+
agent_key: external_exports.string().optional().describe("Agent persona key for the curator caller. Auto-promotion loop passes none (NULL).")
|
|
117617
117661
|
}
|
|
117618
117662
|
},
|
|
117619
117663
|
async (args) => {
|
|
117664
|
+
const agentKeyRaw = args.agent_key ?? process.env.AGENT_KEY ?? null;
|
|
117665
|
+
const agentCuratorId = agentKeyRaw ? await getOrCreateSubject(agentKeyRaw, "agent") : null;
|
|
117620
117666
|
const result = await runCurator({
|
|
117621
117667
|
subjectKey: args.subject_key,
|
|
117622
117668
|
projectKey: args.project_key,
|
|
@@ -117624,7 +117670,8 @@ function registerTools(server) {
|
|
|
117624
117670
|
minClusterSize: args.min_cluster_size,
|
|
117625
117671
|
similarityThreshold: args.similarity_threshold,
|
|
117626
117672
|
minImportance: args.min_importance,
|
|
117627
|
-
maxClusters: args.max_clusters
|
|
117673
|
+
maxClusters: args.max_clusters,
|
|
117674
|
+
agentCuratorId
|
|
117628
117675
|
});
|
|
117629
117676
|
const lines = [];
|
|
117630
117677
|
lines.push(`SKILL CURATOR ${result.dry_run ? "DRY RUN" : "RUN"}`);
|
|
@@ -117726,7 +117773,7 @@ function registerTools(server) {
|
|
|
117726
117773
|
const whereClause = conditions.join(" AND ");
|
|
117727
117774
|
const results = await db.query(
|
|
117728
117775
|
`SELECT f.id, f.content, f.fact_type, f.confidence, f.importance, f.tags, f.created_at,
|
|
117729
|
-
|
|
117776
|
+
m.model_name as author_model,
|
|
117730
117777
|
subj.display_name as subject_name,
|
|
117731
117778
|
proj.display_name as project_name,
|
|
117732
117779
|
CASE WHEN f.embedding IS NOT NULL
|
|
@@ -117753,9 +117800,8 @@ function registerTools(server) {
|
|
|
117753
117800
|
let formatted = baseContext + "\u{1F9E0} Recalled Facts:\n\n";
|
|
117754
117801
|
results.rows.forEach((r) => {
|
|
117755
117802
|
const sim = (r.similarity * 100).toFixed(0);
|
|
117756
|
-
const conf = r.effective_confidence ? `${r.effective_confidence} (eff)` : r.confidence;
|
|
117757
117803
|
const author = r.author_model ? ` | via ${r.author_model}` : "";
|
|
117758
|
-
formatted += `[#${r.id}] [${r.fact_type}] (imp: ${r.importance}, conf: ${
|
|
117804
|
+
formatted += `[#${r.id}] [${r.fact_type}] (imp: ${r.importance}, conf: ${r.confidence}, sim: ${sim}%${author})
|
|
117759
117805
|
`;
|
|
117760
117806
|
if (r.subject_name) formatted += `Subject: ${r.subject_name}`;
|
|
117761
117807
|
if (r.project_name) formatted += ` | Project: ${r.project_name}`;
|