@futdevpro/fdp-agent-memory 1.1.166 → 1.1.194
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/build/package.json +8 -2
- package/build/src/_cli/_commands/prune-duplicates.command.js +93 -0
- package/build/src/_cli/_commands/retire-temporary.command.js +77 -0
- package/build/src/_cli/register-commands.js +4 -0
- package/build/src/_collections/config-catalog.const.js +75 -0
- package/build/src/_models/data-models/fam-entry.data-model.js +6 -0
- package/build/src/_models/data-models/fam-memory.data-model.js +3 -0
- package/build/src/_modules/embedding/_collections/fam-exact-duplicate-prune.util.js +85 -0
- package/build/src/_modules/embedding/_services/fam-embedding-bootstrap.control-service.js +32 -0
- package/build/src/_modules/embedding/_services/fam-entry.data-service.js +21 -0
- package/build/src/_modules/embedding/_services/fam-exact-duplicate-prune.control-service.js +152 -0
- package/build/src/_modules/embedding/index.js +7 -1
- package/build/src/_modules/ingest/_services/fam-ingest.control-service.js +21 -1
- package/build/src/_modules/ingest/_services/fam-scan-job.control-service.js +55 -1
- package/build/src/_modules/ingest/_services/fam-scan-scheduler.control-service.js +26 -0
- package/build/src/_modules/mcp/_collections/fam-core-tools.const.js +11 -0
- package/build/src/_modules/mcp/_services/fam-read-tool.service.js +2 -0
- package/build/src/_modules/mcp/_services/fam-write-tool.service.js +29 -7
- package/build/src/_modules/retrieval/_collections/fam-cross-table-note.util.js +136 -0
- package/build/src/_modules/retrieval/_collections/fam-lexical-match.util.js +75 -2
- package/build/src/_modules/retrieval/_collections/fam-literal-phrase.util.js +74 -0
- package/build/src/_modules/retrieval/_collections/fam-memory-retention.util.js +70 -0
- package/build/src/_modules/retrieval/_services/fam-memory-reactivation.control-service.js +8 -1
- package/build/src/_modules/retrieval/_services/fam-memory-retention.control-service.js +118 -0
- package/build/src/_modules/retrieval/_services/fam-retrieval-candidate.data-service.js +33 -0
- package/build/src/_modules/retrieval/_services/fam-retrieval.control-service.js +224 -5
- package/build/src/_modules/retrieval/index.js +6 -1
- package/build/src/_routes/server/api/api.controller.js +77 -15
- package/package.json +8 -2
- package/build/src/_integration-tests/_helpers/fam-integration-test-setup.util.js +0 -105
|
@@ -69,6 +69,8 @@ class Api_Controller extends nts_dynamo_1.DyNTS_Controller {
|
|
|
69
69
|
this.statsTableEndpoint(),
|
|
70
70
|
this.ingestRunsEndpoint(),
|
|
71
71
|
this.duplicatesEndpoint(),
|
|
72
|
+
this.duplicatesPruneEndpoint(),
|
|
73
|
+
this.memoryRetireEndpoint(),
|
|
72
74
|
this.configGetEndpoint(),
|
|
73
75
|
this.configSetEndpoint(),
|
|
74
76
|
this.scanStartEndpoint(),
|
|
@@ -521,22 +523,26 @@ class Api_Controller extends nts_dynamo_1.DyNTS_Controller {
|
|
|
521
523
|
continue;
|
|
522
524
|
}
|
|
523
525
|
const collection = this.entryCollection(registryEntry);
|
|
524
|
-
|
|
525
|
-
//
|
|
526
|
+
// FIX (2026-09-02, COLLSCAN → index): a korábbi `countDocuments({})` + `$group embeddingStatus`
|
|
527
|
+
// TELJES collection-átolvasás volt (350k+ doc a nagy tárakon) — meleg Mongo-cache mellett
|
|
528
|
+
// észrevétlen, kihűlt cache + telített lemez mellett viszont 20–50 s/tár, és a `/stats` a UI
|
|
529
|
+
// landing alatt PERCEKIG lógott (mérve: 120 s+ timeout). Most:
|
|
530
|
+
// • darabszám: `estimatedDocumentCount` (collection-metaadat, ~0 ms — a stats-kártyának a
|
|
531
|
+
// nagyságrend kell, nem a tranzakció-pontos szám),
|
|
532
|
+
// • státusz-bontás: per-státusz `countDocuments({embeddingStatus})` — az indexből számol
|
|
533
|
+
// (COUNT_SCAN), doc-olvasás nélkül,
|
|
534
|
+
// • utolsó módosítás: a friss `__lastModified` index tetejéről egyetlen doc.
|
|
535
|
+
const count = await collection.estimatedDocumentCount();
|
|
526
536
|
const byStatus = { pending: 0, completed: 0, error: 0 };
|
|
527
|
-
const
|
|
528
|
-
.
|
|
529
|
-
.
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
byStatus.pending += group.n;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
// Utolsó módosítás: EGYETLEN doc (a legfrissebb), csak az időbélyeg-mezőre projektálva.
|
|
537
|
+
const [completed, error] = await Promise.all([
|
|
538
|
+
collection.countDocuments({ embeddingStatus: 'completed' }),
|
|
539
|
+
collection.countDocuments({ embeddingStatus: 'error' }),
|
|
540
|
+
]);
|
|
541
|
+
byStatus.completed = completed;
|
|
542
|
+
byStatus.error = error;
|
|
543
|
+
// A `pending` a maradék (beleértve a státusz-mentes régi doc-okat) — így nem kell harmadik scan.
|
|
544
|
+
byStatus.pending = Math.max(0, count - completed - error);
|
|
545
|
+
// Utolsó módosítás: EGYETLEN doc a `__lastModified` index tetejéről (2026-09-02 óta indexelt).
|
|
540
546
|
const newest = await collection
|
|
541
547
|
.find({}, { projection: { __lastModified: 1 } })
|
|
542
548
|
.sort({ __lastModified: -1 })
|
|
@@ -627,6 +633,62 @@ class Api_Controller extends nts_dynamo_1.DyNTS_Controller {
|
|
|
627
633
|
});
|
|
628
634
|
}
|
|
629
635
|
// =========================================================================
|
|
636
|
+
// /duplicates/prune — BÁJTAZONOS ismétlés-nyesés (dry-run az alapértelmezés)
|
|
637
|
+
// =========================================================================
|
|
638
|
+
/**
|
|
639
|
+
* `POST /duplicates/prune` — az azonos `(absolutePath, chunkIndex, chunkTotal, contentHash)` négyesű
|
|
640
|
+
* példányokból a legfrissebbet megtartja, a többit soft-delete-eli, és a csoport `recallCount` /
|
|
641
|
+
* `lastRecalledAt` MAXIMUMÁT a megtartottra viszi. Body: `table` (opcionális, különben MINDEN tár),
|
|
642
|
+
* `dryRun` (DEFAULT `true` — törölni csak explicit `false`-szal lehet), `maxGroups`.
|
|
643
|
+
*
|
|
644
|
+
* A `GET /duplicates/:table`-lel NEM keverendő: az szemantikus hasonlóságot keres és sosem töröl.
|
|
645
|
+
*/
|
|
646
|
+
duplicatesPruneEndpoint() {
|
|
647
|
+
return new nts_dynamo_1.DyNTS_Endpoint_Params({
|
|
648
|
+
name: 'duplicatesPrune',
|
|
649
|
+
type: fsm_dynamo_1.DyFM_HttpCallType.post,
|
|
650
|
+
endpoint: '/duplicates/prune',
|
|
651
|
+
tasks: [
|
|
652
|
+
async (req, res) => {
|
|
653
|
+
await this.run(res, async () => {
|
|
654
|
+
const body = req.body ?? {};
|
|
655
|
+
return embedding_1.FAM_ExactDuplicatePrune_ControlService.getInstance().prune({
|
|
656
|
+
table: body.table ? this.parseTable(body.table) : undefined,
|
|
657
|
+
dryRun: body.dryRun !== false,
|
|
658
|
+
maxGroups: typeof body.maxGroups === 'number' ? body.maxGroups : undefined,
|
|
659
|
+
});
|
|
660
|
+
});
|
|
661
|
+
},
|
|
662
|
+
],
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
// =========================================================================
|
|
666
|
+
// /memory/retire-temporary — az alvó törmelék nyugdíjazása (dry-run az alapértelmezés)
|
|
667
|
+
// =========================================================================
|
|
668
|
+
/**
|
|
669
|
+
* `POST /memory/retire-temporary` — az alvó beszélgetés-törmelék (`user_prompt` / `temporary_context`)
|
|
670
|
+
* nyugdíjazása a `memory` táron: `superseded + retiredAt`, NEM törlés. A szabály és az indoklás a
|
|
671
|
+
* `fam-memory-retention.util.ts`-ben. Body: `dryRun` (DEFAULT `true`), `retireAfterDays` (override).
|
|
672
|
+
*/
|
|
673
|
+
memoryRetireEndpoint() {
|
|
674
|
+
return new nts_dynamo_1.DyNTS_Endpoint_Params({
|
|
675
|
+
name: 'memoryRetireTemporary',
|
|
676
|
+
type: fsm_dynamo_1.DyFM_HttpCallType.post,
|
|
677
|
+
endpoint: '/memory/retire-temporary',
|
|
678
|
+
tasks: [
|
|
679
|
+
async (req, res) => {
|
|
680
|
+
await this.run(res, async () => {
|
|
681
|
+
const body = req.body ?? {};
|
|
682
|
+
return retrieval_1.FAM_MemoryRetention_ControlService.getInstance().retire({
|
|
683
|
+
dryRun: body.dryRun !== false,
|
|
684
|
+
retireAfterDays: typeof body.retireAfterDays === 'number' ? body.retireAfterDays : undefined,
|
|
685
|
+
});
|
|
686
|
+
});
|
|
687
|
+
},
|
|
688
|
+
],
|
|
689
|
+
});
|
|
690
|
+
}
|
|
691
|
+
// =========================================================================
|
|
630
692
|
// /config — scoped config olvasás/írás (dsgn-007; a UI settings + CLI config)
|
|
631
693
|
// =========================================================================
|
|
632
694
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@futdevpro/fdp-agent-memory",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.194",
|
|
4
4
|
"description": "Local-first, vector-backed multi-table agent memory exposed as an MCP server (read/write/capabilities). Public, FDP-Templates-free, no auth.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -19,7 +19,13 @@
|
|
|
19
19
|
"build",
|
|
20
20
|
"client-dist",
|
|
21
21
|
"README.md",
|
|
22
|
-
"LICENSE"
|
|
22
|
+
"LICENSE",
|
|
23
|
+
"!build/**/*.spec.js",
|
|
24
|
+
"!build/**/*.spec.js.map",
|
|
25
|
+
"!build/**/*.spec.d.ts",
|
|
26
|
+
"!build/**/_benchmarks/**",
|
|
27
|
+
"!build/**/_integration-tests/**",
|
|
28
|
+
"!build/**/_spec-support/**"
|
|
23
29
|
],
|
|
24
30
|
"engines": {
|
|
25
31
|
"node": ">=20"
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FAM_IntegrationTest_Setup_Util = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const net = tslib_1.__importStar(require("net"));
|
|
6
|
-
const mongoose_1 = tslib_1.__importDefault(require("mongoose"));
|
|
7
|
-
const nts_dynamo_1 = require("@futdevpro/nts-dynamo");
|
|
8
|
-
const fam_db_models_const_1 = require("../../_collections/fam-db-models.const");
|
|
9
|
-
/** Integrációs teszt issuer — a MongoDB-dokumentumok azonosítására. */
|
|
10
|
-
const INTTEST_ISSUER = 'integration-test';
|
|
11
|
-
/** Teszt-adat prefix — a teszt-dokumentumok megkülönböztetésére (NEM ütközik production-nal). */
|
|
12
|
-
const INTTEST_PREFIX = 'inttest-';
|
|
13
|
-
/** A dedikált spec-DB neve (a runner/local Mongo-n; NEM a `fdp-agent-memory` prod-DB). */
|
|
14
|
-
const INTTEST_DB_NAME = 'fam_inttest';
|
|
15
|
-
/** MongoDB elérhetőség-ellenőrzés timeout (ms). */
|
|
16
|
-
const MONGO_CHECK_TIMEOUT_MS = 1500;
|
|
17
|
-
/**
|
|
18
|
-
* `FAM_IntegrationTest_Setup_Util` — az integrációs tesztek közös setup-utility-je (a
|
|
19
|
-
* `ccap-revisioned` `IntegrationTest_Setup_Util` mintára). MongoDB-elérhetőség (TCP-probe a
|
|
20
|
-
* `MONGO_URL`-re), egyedi `inttest-` ID-generálás, ÉS egy **lightweight DB-setup** (mongoose-connect +
|
|
21
|
-
* `DyNTS_GlobalService.setServices`) — **NEM a teljes `new App()` boot** (az HTTP-listen + LVS-hydrate
|
|
22
|
-
* postProcess-t indít, ami a spec-eket hangolja); csak a DataService-ek DB-rétegét állítja fel.
|
|
23
|
-
*/
|
|
24
|
-
class FAM_IntegrationTest_Setup_Util {
|
|
25
|
-
/** Teszt issuer azonosító — minden integrációs-teszt DataService-híváshoz. */
|
|
26
|
-
static getIssuer() {
|
|
27
|
-
return INTTEST_ISSUER;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Egyedi, időbélyeges ID/tartalom a teszt-adatokhoz. Pattern: `inttest-{timestamp}-{random}` —
|
|
31
|
-
* párhuzamos futtatásban is egyedi, és a prefix jelzi a teszt-adatot.
|
|
32
|
-
*/
|
|
33
|
-
static generateUniqueId() {
|
|
34
|
-
const timestamp = Date.now();
|
|
35
|
-
const random = Math.random().toString(36).substring(2, 8);
|
|
36
|
-
return `${INTTEST_PREFIX}${timestamp}-${random}`;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* MongoDB elérhetőség TCP-socket-tel (a `MONGO_URL` host:port-ja; default
|
|
40
|
-
* `mongodb://127.0.0.1:27017`). Ha nem elérhető → `false`, és a tesztek `pending()`-re állnak
|
|
41
|
-
* (CI-ben Mongo nélkül is zöld a suite — pending, NEM failure).
|
|
42
|
-
*/
|
|
43
|
-
static checkMongoAvailability() {
|
|
44
|
-
return new Promise((resolve) => {
|
|
45
|
-
const mongoUrl = process.env.MONGO_URL ?? 'mongodb://127.0.0.1:27017';
|
|
46
|
-
const urlNoProtocol = mongoUrl.replace(/^mongodb(\+srv)?:\/\//, '');
|
|
47
|
-
const hostPort = urlNoProtocol.split('/')[0];
|
|
48
|
-
const parts = hostPort.split(':');
|
|
49
|
-
const host = parts[0];
|
|
50
|
-
const port = parseInt(parts[1] ?? '27017', 10);
|
|
51
|
-
const socket = net.createConnection({ host: host, port: port });
|
|
52
|
-
let finished = false;
|
|
53
|
-
const finish = (available) => {
|
|
54
|
-
if (finished) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
finished = true;
|
|
58
|
-
try {
|
|
59
|
-
socket.destroy();
|
|
60
|
-
}
|
|
61
|
-
catch { /* ignore */ }
|
|
62
|
-
resolve(available);
|
|
63
|
-
};
|
|
64
|
-
socket.on('connect', () => { finish(true); });
|
|
65
|
-
socket.on('error', () => { finish(false); });
|
|
66
|
-
setTimeout(() => { finish(false); }, MONGO_CHECK_TIMEOUT_MS);
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Lightweight DB-setup (`beforeAll`-ban, ha a Mongo elérhető): mongoose-connect a dedikált
|
|
71
|
-
* `fam_inttest` DB-re + `DyNTS_GlobalService.setServices` a `FAM_DB_MODELS`-szel (SSOT). Így a
|
|
72
|
-
* `new FAM_*_DataService(...)` (eager getDBService) feloldódik — App-boot, HTTP-listen és
|
|
73
|
-
* embedding/LVS-postProcess NÉLKÜL (azok a teljes boot velejárói, itt nem kellenek).
|
|
74
|
-
*/
|
|
75
|
-
static async setupDb() {
|
|
76
|
-
const mongoUrl = process.env.MONGO_URL ?? 'mongodb://127.0.0.1:27017';
|
|
77
|
-
const base = mongoUrl.replace(/^(mongodb(\+srv)?:\/\/[^/]+).*$/, '$1');
|
|
78
|
-
await mongoose_1.default.connect(`${base}/${INTTEST_DB_NAME}`);
|
|
79
|
-
await nts_dynamo_1.DyNTS_GlobalService.setServices({ dbModels: fam_db_models_const_1.FAM_DB_MODELS });
|
|
80
|
-
}
|
|
81
|
-
/** DB-teardown (`afterAll`-ban): a mongoose-kapcsolat zárása (best-effort). */
|
|
82
|
-
static async teardownDb() {
|
|
83
|
-
try {
|
|
84
|
-
if (mongoose_1.default.connection.readyState !== 0) {
|
|
85
|
-
await mongoose_1.default.disconnect();
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
catch {
|
|
89
|
-
// best-effort — a process-vég úgyis bontja.
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
/** Egy collection ürítése teszt KÖZÖTT (a teszt-izolációhoz). No-op ha a kapcsolat nem áll. */
|
|
93
|
-
static async clearCollection(collectionName) {
|
|
94
|
-
if (mongoose_1.default.connection.readyState !== 1) {
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
try {
|
|
98
|
-
await mongoose_1.default.connection.collection(collectionName).deleteMany({});
|
|
99
|
-
}
|
|
100
|
-
catch {
|
|
101
|
-
// a collection lehet hogy még nem létezik — nem hiba.
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
exports.FAM_IntegrationTest_Setup_Util = FAM_IntegrationTest_Setup_Util;
|