@futdevpro/fdp-agent-memory 1.1.137 → 1.1.153
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 +1 -1
- package/build/src/_collections/config-catalog.const.js +58 -19
- package/build/src/_collections/fam-agent-guidance.util.js +1 -1
- package/build/src/_collections/fam-mcp-bridge.util.js +45 -4
- package/build/src/_modules/embedding/_services/fam-hydration-coordinator.control-service.js +14 -3
- package/build/src/_modules/ingest/_services/fam-scan-job.control-service.js +47 -0
- package/build/src/_modules/mcp/_collections/fam-read-response-shape.util.js +19 -4
- package/build/src/_modules/mcp/_services/fam-read-tool.service.js +44 -1
- package/build/src/_modules/mcp/_services/fam-write-tool.service.js +23 -0
- package/build/src/_modules/retrieval/_collections/fam-lexical-match.util.js +36 -5
- package/build/src/_modules/retrieval/_collections/fam-result-diversity.util.js +128 -0
- package/build/src/_modules/retrieval/_services/fam-retrieval-suggestions.util.js +14 -2
- package/build/src/_modules/retrieval/_services/fam-retrieval.control-service.js +52 -16
- package/build/src/_modules/retrieval/index.js +2 -1
- package/package.json +1 -1
package/build/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@futdevpro/fdp-agent-memory",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.153",
|
|
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": {
|
|
@@ -138,19 +138,49 @@ exports.CONFIG_CATALOG = {
|
|
|
138
138
|
description: 'Minimum similarity-score küszöb (CCAP default 0 = nincs vágás).',
|
|
139
139
|
},
|
|
140
140
|
'read.hydrationWaitMs': {
|
|
141
|
-
type: 'number', default:
|
|
141
|
+
type: 'number', default: 20000, min: 0, max: 600000, integer: true, levels: ALL_LEVELS,
|
|
142
142
|
description: 'A readiness-coordinator hidratálás-bevárás felső korlátja ms-ban: a `read`/`search` MEGVÁRJA a '
|
|
143
143
|
+ 'tár pool-jának (kezdő VAGY újra-) hidratálását ahelyett, hogy `FAM-VEC-SEARCH-001 pool ÜRES`-t dobna. '
|
|
144
|
-
+ '0 = nincs várakozás (azonnali hiba, ha még nem kész).
|
|
145
|
-
+ '
|
|
144
|
+
+ '0 = nincs várakozás (azonnali hiba, ha még nem kész). '
|
|
145
|
+
+ 'MÉRT INDOK a 20s-re (2026-08-22): a korábbi default 180s volt, ám EGYETLEN MCP-kliensnek sincs ilyen '
|
|
146
|
+
+ 'hosszú tool-timeoutja (a Codex 60s-mal futott) — vagyis a szerver egy nem létező hívóra várt, és a '
|
|
147
|
+
+ 'jól diagnosztizálható „a pool hidratál, 3/6 tár kész" állapotot ÁTLÁTHATATLAN kliens-oldali timeoutra '
|
|
148
|
+
+ 'fordította. Egy agent három azonos újrapróbálkozással 3 percet égetett el úgy, hogy az okot SOHA nem '
|
|
149
|
+
+ 'láthatta. 20s továbbra is elnyeli a rövid újra-hidratálási zökkenőt, de a TELJES hideg bootot (~120s) '
|
|
150
|
+
+ 'már nem rejti el: azt a hívónak TUDNIA kell, hogy dönthessen (vár, vagy közben mást csinál). '
|
|
151
|
+
+ 'A time-out hibája megmondja, mely tárak vannak még hátra. Aki a régi viselkedést akarja, állítsa vissza.',
|
|
152
|
+
},
|
|
153
|
+
'read.maxChunksPerFile': {
|
|
154
|
+
type: 'number', default: 2, min: 0, max: 50, integer: true, levels: ALL_LEVELS,
|
|
155
|
+
description: 'Fajlonkent legfeljebb ennyi chunk kerul a top-K elejere; a tobbi a lista vegere csuszik '
|
|
156
|
+
+ '(0 = kikapcsolva, talalat SOHA nem vesz el). Mert indok (2026-08-22): a top-K slotok 44%-a ugyanannak '
|
|
157
|
+
+ 'a fajlnak egy masik darabja volt, egy query-n a TELJES top-5 egyetlen fajlbol allt.',
|
|
158
|
+
},
|
|
159
|
+
'read.tableMinShare': {
|
|
160
|
+
type: 'number', default: 1, min: 0, max: 20, integer: true, levels: ALL_LEVELS,
|
|
161
|
+
description: 'Tobb-taras query-ben minden talalatot ado tar garantalt helye a top-K-ban (0 = kikapcsolva). '
|
|
162
|
+
+ 'Mert indok (2026-08-22): kontrollalt teszten a rules tar 0/3 aranyban tunt el a documents mogott, '
|
|
163
|
+
+ 'holott a csak-rules query azonnal hozta a kanonikus szabalyt.',
|
|
146
164
|
},
|
|
147
165
|
'read.relevanceFloor': {
|
|
148
|
-
type: 'number', default: 0.
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
166
|
+
type: 'number', default: 0.60, min: 0.0, max: 1.0, levels: ALL_LEVELS,
|
|
167
|
+
// PER-TÁR kalibráció (2026-08-14 MÉRÉS): a tárak score-tartománya ELTÉR — a `codebase`/`documents` szimbólum-
|
|
168
|
+
// és cím-egyezései magasabbra futnak (top 0.75-0.84), a `rules`/`memory` prózai egyezései alacsonyabbra
|
|
169
|
+
// (top 0.64-0.66). Egységes küszöbbel az egyik tár túl engedékeny, a másik túl szigorú lenne.
|
|
170
|
+
defaultsByTable: {
|
|
171
|
+
[fam_table_type_enum_1.FAM_Table.codebase]: 0.65,
|
|
172
|
+
[fam_table_type_enum_1.FAM_Table.documents]: 0.65,
|
|
173
|
+
// A `rules` korpusz ANGOL próza, a kérdések viszont jórészt MAGYARUL érkeznek → a cosine
|
|
174
|
+
// rendszeresen alacsonyabb. MÉRVE (8 valós, JÓ query): a 0.60-as floor mellett 4/8 query azt
|
|
175
|
+
// jelentette volna, hogy „0 magabiztos találat" — HOLOTT a helyes szabály a #1 volt. 0.52-nél 1/8.
|
|
176
|
+
[fam_table_type_enum_1.FAM_Table.rules]: 0.52,
|
|
177
|
+
},
|
|
178
|
+
description: 'Confidence-padló a NYERS cosine score-on: a relevancia-jelzések (`totalRelevant` / dense / '
|
|
179
|
+
+ 'suggestions) alapja. **MÉRVE (2026-08-14):** a korábbi `0.5` a `memory` táron 500 tételt jelölt '
|
|
180
|
+
+ '„magabiztosan relevánsnak" (a valódi egyezések 0.60 FÖLÖTT voltak) — a szám így nem információ volt, '
|
|
181
|
+
+ 'hanem zaj, és a dense-jelzés is folyamatosan tüzelt. A `0.60` (codebase/documents `0.65`) a mért '
|
|
182
|
+
+ 'eloszlásból jön. FONTOS: ez a jelzéseket kalibrálja, NEM dobja el a találatokat — a hit-eket a '
|
|
183
|
+
+ '`read.minScore` szűri (best-effort recall marad).',
|
|
154
184
|
},
|
|
155
185
|
'read.importChunkWeight': {
|
|
156
186
|
type: 'number', default: 0.4, min: 0.0, max: 1.0, levels: ALL_LEVELS,
|
|
@@ -160,6 +190,17 @@ exports.CONFIG_CATALOG = {
|
|
|
160
190
|
+ 'importChunkWeight` a definíció-chunkok ALÁ rangsorolja őket. READ-time (nincs re-embed); a nyers '
|
|
161
191
|
+ 'cosine score (relevancia-jelzések) NEM változik, csak a ranking. 1 = nincs csökkentés.',
|
|
162
192
|
},
|
|
193
|
+
'read.weightInfluence': {
|
|
194
|
+
type: 'number', default: 0.06, min: 0.0, max: 1.0, levels: ALL_LEVELS,
|
|
195
|
+
description: 'A statikus `weight` BEFOLYÁSA a rangsorra (2026-08-14 lelet). A `finalScore` eddig LINEÁRISAN '
|
|
196
|
+
+ 'szorzott a weight-tel, a koszinusz viszont csak ~0.3-0.8 között mozog — ezért egy `weight:5` tétel '
|
|
197
|
+
+ 'MATEMATIKAILAG VERHETETLEN volt: mérve a `rules` táron 2 db w5-ös bejegyzés ült MINDEN szabály-keresés '
|
|
198
|
+
+ 'tetején (score 0.519 × 5 = 2.595 vs. a helyes találat 0.621 × 1 = 0.742). Az effektív súly mostantól '
|
|
199
|
+
+ '`1 + weightInfluence × (weight - 1)` — vagyis a weight DÖNTETLENT BONT (a kurált tartalom felé), de NEM '
|
|
200
|
+
+ 'írja felül a szemantikai relevanciát. `0.12` → w5 ≈ 1.48 · w3 ≈ 1.24 · w2 ≈ 1.12. `1.0` = a régi, '
|
|
201
|
+
+ 'lineáris viselkedés; `0` = a weight teljesen figyelmen kívül. Az azonos súlyú tételek egymáshoz '
|
|
202
|
+
+ 'viszonyított sorrendje VÁLTOZATLAN (a tár-belső rangsort nem érinti).',
|
|
203
|
+
},
|
|
163
204
|
'read.importSourceWeight': {
|
|
164
205
|
type: 'number', default: 0.85, min: 0.0, max: 1.0, levels: ALL_LEVELS,
|
|
165
206
|
description: 'Az import-FORRÁSÚ (`source.type:"import"`, pl. claude-mem-import) entry-k read-idejű rangsor-'
|
|
@@ -177,16 +218,14 @@ exports.CONFIG_CATALOG = {
|
|
|
177
218
|
+ '(régi viselkedés). Default 0.6.',
|
|
178
219
|
},
|
|
179
220
|
'read.scanSummaryWeight': {
|
|
180
|
-
type: 'number', default:
|
|
181
|
-
description: 'A `
|
|
182
|
-
+ '
|
|
183
|
-
+ '
|
|
184
|
-
+ '
|
|
185
|
-
+ '
|
|
186
|
-
+ '
|
|
187
|
-
+ '
|
|
188
|
-
+ 'regresszió). READ-time (nincs re-embed); a nyers cosine + a `weight` DTO-mező NEM változik, csak a ranking. '
|
|
189
|
-
+ 'A stored weight ALÁ csökkenteni is lehet (<1) az agresszívabb leszorításhoz; ≥ stored weight = kikapcsolva.',
|
|
221
|
+
type: 'number', default: 0.8, min: 0, max: 10, levels: ALL_LEVELS,
|
|
222
|
+
description: 'A `scan-summary` forrasu bejegyzesek (fs-summary konyvtar-listak) EFFEKTIV suly-plafonja. '
|
|
223
|
+
+ 'Ezek atlagosan ~22 000 karakteres fajlnev-listak `weight: 2`-vel, es mivel egy repo MINDEN fajlnevet '
|
|
224
|
+
+ 'tartalmazzak, gyakorlatilag BARMIRE illeszkednek. Mert kalibracio (2026-08-22, 12 zaj- + 3 jogos '
|
|
225
|
+
+ 'navigacios query): 1.0 eseten a top-K slotok 35%-a fs-summary szemet volt (2 query-n a TOP-1 is); '
|
|
226
|
+
+ '0.9 eseten 20%; 0.8 eseten 5% UGY, hogy a jogos "mi van ebben a repoban" kerdes tovabbra is '
|
|
227
|
+
+ '3/3-ban megtalalja; 0.7 alatt a zaj mar 0%, DE a jogos navigacio is romlani kezd (2/3, majd 1/3). '
|
|
228
|
+
+ 'Ezert 0.8 az optimum. A cap a TEMPERALT (effectiveWeight) sulyra hat.',
|
|
190
229
|
},
|
|
191
230
|
'read.denseResultRatio': {
|
|
192
231
|
type: 'number', default: 2.0, min: 1.0, max: 50.0, levels: ALL_LEVELS,
|
|
@@ -33,7 +33,7 @@ class FAM_AgentGuidance_Util {
|
|
|
33
33
|
/** A `read` tool minimál, helyes hívása (a leggyakoribb szándék). */
|
|
34
34
|
static READ_EXAMPLE = '{"queries":[{"tables":["knowledge"],"query":"amit keresel","topK":5}]}';
|
|
35
35
|
/** A `write` tool minimál, helyes hívása. */
|
|
36
|
-
static WRITE_EXAMPLE = '{"operation":"create","table":"memory","content":"a megjegyzendő tudás","scopePath":[{"layer":"project","
|
|
36
|
+
static WRITE_EXAMPLE = '{"operation":"create","table":"memory","content":"a megjegyzendő tudás","scopePath":[{"layer":"project","rawName":"<projekt>"}]}';
|
|
37
37
|
/**
|
|
38
38
|
* A JSON-parse hiba KONKRÉT okának felismerése a nyers body-ból (PURE). A body-parser üzenete önmagában
|
|
39
39
|
* (`Expected property name or '}' at position 1`) egy agentnek keveset mond — a tényleges minta viszont
|
|
@@ -34,16 +34,26 @@ class FAM_McpBridge_Util {
|
|
|
34
34
|
handler: async (args) => {
|
|
35
35
|
let result = await client.post(`/api/${tool.name}`, args ?? {});
|
|
36
36
|
// ÖNHEAL (user-FR 2026-06-22): ha a primary időközben leesett (`unreachable`), NE bukjunk némán —
|
|
37
|
-
// automatikusan felhúzzuk a leválasztott primary-t (`ensureRunning`) és EGYSZER újrapróbáljuk.
|
|
38
|
-
// primary épp bootol (pool-hidratálás), tiszta „indul, próbáld újra" hibát adunk (a következő hívás megy).
|
|
37
|
+
// automatikusan felhúzzuk a leválasztott primary-t (`ensureRunning`) és EGYSZER újrapróbáljuk.
|
|
39
38
|
if (!result.ok && result.unreachable) {
|
|
40
39
|
const ensured = await serve_command_1.FAM_Serve_Util.ensureRunning();
|
|
41
40
|
if (ensured.running) {
|
|
42
41
|
result = await client.post(`/api/${tool.name}`, args ?? {});
|
|
43
42
|
}
|
|
44
43
|
else if (ensured.reason === 'boot-timeout') {
|
|
45
|
-
throw new Error(
|
|
46
|
-
|
|
44
|
+
throw new Error(`FAM-MCP-BRIDGE-002: ${await FAM_McpBridge_Util.bootHint(client)}`);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
// A leválasztott indítás NEM sikerült (`no-entry` / `spawn-failed` / `remote-unreachable`).
|
|
48
|
+
// Eddig ez a generikus „a REST-hívás sikertelen" ágra esett, amiből az agent NEM tudhatta meg,
|
|
49
|
+
// hogy egyáltalán KELL egy szervert indítani, se azt, MIVEL (2026-08-22 owner-lelet).
|
|
50
|
+
throw new Error(`FAM-MCP-BRIDGE-003: A FAM primary NEM fut, és az automatikus indítás sem `
|
|
51
|
+
+ `sikerült (ok: ${ensured.reason}; cél: ${ensured.url}). A FAM-nak szüksége van egy futó `
|
|
52
|
+
+ 'primary-ra — indítsd el KÉZZEL, egyszer, és utána minden MCP-hívás működik: '
|
|
53
|
+
+ '`fam serve` (állandó, leválasztott szerver; a session-öket túléli). '
|
|
54
|
+
+ 'Diagnózis: `fam doctor`, vagy `GET http://127.0.0.1:39265/api/health`. '
|
|
55
|
+
+ 'Ha a port foglalt egy fél-halott processzel, azt előbb állítsd le. '
|
|
56
|
+
+ 'Addig NE jelentsd a FAM-ot elérhetetlennek — a REST-felület ugyanezen a porton él.');
|
|
47
57
|
}
|
|
48
58
|
}
|
|
49
59
|
if (!result.ok) {
|
|
@@ -59,5 +69,36 @@ class FAM_McpBridge_Util {
|
|
|
59
69
|
}
|
|
60
70
|
await adapter.startStdio();
|
|
61
71
|
}
|
|
72
|
+
/**
|
|
73
|
+
* A „most bootol" hibaüzenet ÉLŐ boot-állapottal. Mért indok (2026-08-22): a korábbi szöveg annyit mondott, hogy
|
|
74
|
+
* „próbáld újra pár másodperc múlva" — miközben a hideg boot MÉRVE ~70–120 s (~338k vektor / ~9 GB). Az agent ezt
|
|
75
|
+
* szó szerint vette, pár másodpercenként újrapróbált, végig bukott, és ebből arra jutott, hogy a FAM hibás. A
|
|
76
|
+
* „pár másodperc" tehát nem pontatlanság volt, hanem AKTÍVAN félrevezető: pont abba a mintába lökte, ami nem
|
|
77
|
+
* segíthet. Ezért az üzenet most (a) megmondja, hol tart a boot, (b) őszinte nagyságrendet ad, (c) a
|
|
78
|
+
* `/api/health`-re irányít a lekérdezés-ismételgetés HELYETT (`core-error-debuggable`).
|
|
79
|
+
*/
|
|
80
|
+
static async bootHint(client) {
|
|
81
|
+
// A `client.get` NEM dob a nem-elérhető szerverre, hanem `ok:false`-t ad — ezért az „még nem lekérdezhető"
|
|
82
|
+
// ágat EXPLICITEN kezelni kell, különben a legkorábbi (leghidegebb) hívásnál épp a helyzet-információ marad ki.
|
|
83
|
+
let progress = ' (A boot-állapot még nem lekérdezhető — a REST-felület sem áll fel; ez a boot legelső '
|
|
84
|
+
+ 'másodperceiben normális.)';
|
|
85
|
+
try {
|
|
86
|
+
const health = await client.get('/api/health');
|
|
87
|
+
const hydration = health.ok ? health.data?.hydration : undefined;
|
|
88
|
+
if (hydration) {
|
|
89
|
+
progress = ` Boot-állapot: ${hydration.hydratedTables ?? '?'}/${hydration.totalTables ?? '?'} tár kész`
|
|
90
|
+
+ `${hydration.pendingTables?.length ? ` — hátra van: ${hydration.pendingTables.join(', ')}` : ''}.`;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// marad az alapértelmezett „még nem lekérdezhető" szöveg
|
|
95
|
+
}
|
|
96
|
+
return 'A FAM primary MOST INDUL, a vektor-pool hidratál — az auto-indítás már elfutott (leválasztva), '
|
|
97
|
+
+ `tehát NEKED nem kell szervert indítanod.${progress} `
|
|
98
|
+
+ 'A hideg boot MÉRVE ~2 perc (~338 ezer vektor, ~9 GB), NEM „pár másodperc". '
|
|
99
|
+
+ 'NE ismételgesd ezt a hívást — nézd a készenlétet: `GET http://127.0.0.1:39265/api/health` '
|
|
100
|
+
+ '(`ready` + `hydration.pendingTables`), és addig dolgozz máson. '
|
|
101
|
+
+ 'Ha előre el akarod kerülni ezt az ablakot, indítsd a FAM-ot a session ELEJÉN: `fam serve`.';
|
|
102
|
+
}
|
|
62
103
|
}
|
|
63
104
|
exports.FAM_McpBridge_Util = FAM_McpBridge_Util;
|
|
@@ -103,9 +103,20 @@ class FAM_HydrationCoordinator_ControlService {
|
|
|
103
103
|
const limitMs = timeoutMs ?? this.waitTimeoutMs;
|
|
104
104
|
const ready = await this.raceWithTimeout(entry.promise, limitMs);
|
|
105
105
|
if (!ready) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
// A hiba a TELJES boot-képet viszi (mely tárak készek / melyik van hátra). Mért indok (2026-08-22):
|
|
107
|
+
// e nélkül a hívó csak egy csupasz timeoutot lát, és nem tudja megkülönböztetni a „most bootol" és a
|
|
108
|
+
// „elromlott" esetet — egy agent emiatt háromszor ismételte ugyanazt a lekérdezést, majd HIBÁSAN arra
|
|
109
|
+
// jutott, hogy a FAM végig egészséges volt, és csak a saját kliens-plafonja kevés (`core-error-debuggable`).
|
|
110
|
+
const shot = this.snapshot();
|
|
111
|
+
const readyTables = shot.filter((s) => s.state === 'ready').map((s) => s.table);
|
|
112
|
+
const waiting = shot.filter((s) => s.state !== 'ready').map((s) => `${s.table}:${s.state}`);
|
|
113
|
+
throw this.hydrationError(table, `A tár hidratálása ${Math.round(limitMs / 1000)}s alatt nem fejeződött be. `
|
|
114
|
+
+ `Boot-állapot: ${readyTables.length}/${shot.length} tár kész`
|
|
115
|
+
+ `${waiting.length ? ` — hátra van: ${waiting.join(', ')}` : ''}. `
|
|
116
|
+
+ 'Ez NEM hiba és NEM a te hívásod mérete: a pool-hidratálás fut (hideg boot-kor a nagy tárak '
|
|
117
|
+
+ 'ÖSSZESEN percekig tartanak). NE ismételd ugyanazt a lekérdezést — várd meg a készenlétet a '
|
|
118
|
+
+ '`GET /api/health` `ready` / `hydration.pendingTables` mezőin, VAGY dolgozz addig máson. '
|
|
119
|
+
+ 'A várakozási korlát a `read.hydrationWaitMs` configgal állítható.');
|
|
109
120
|
}
|
|
110
121
|
}
|
|
111
122
|
/** Egy tár aktuális állapota (diag / health / teszt). */
|
|
@@ -379,6 +379,21 @@ class FAM_ScanJob_ControlService {
|
|
|
379
379
|
return resumed;
|
|
380
380
|
}
|
|
381
381
|
/** A default per-projekt futtató: a meglévő `scan-project` write-handler az operation-queue-n át. */
|
|
382
|
+
/**
|
|
383
|
+
* Egy scan-cel kimenetenek OSZTALYOZASA (pure) — a nema elavulas elleni kapu.
|
|
384
|
+
*
|
|
385
|
+
* Mert lelet (2026-08-22): a heti re-scan HAROM egymast koveto heten (aug 3/10/17) bukott a `documentations` es az
|
|
386
|
+
* `OGS-projects\documents` mappakra, mert azokat atneveztek (`fdp-documentations` / `ogs-documents`), de a job
|
|
387
|
+
* cel-listaja a REGI utvonalat vitte tovabb. A runner viszont mindig `ok`-ot adott vissza, ha a hivas nem dobott —
|
|
388
|
+
* igy a job `53/53 ok`-kent zarult, es a FAM KET HONAPIG a juniusi doktrinat szolgalta ki ugy, hogy ez sehol nem
|
|
389
|
+
* latszott. A `filesProcessed: 0` ugyanezt jelenti egy letezo utvonalon (rossz include/exclude vagy tul ago ignore).
|
|
390
|
+
*/
|
|
391
|
+
static classifyTargetOutcome(set) {
|
|
392
|
+
if (!set.pathExists) {
|
|
393
|
+
return 'missing-path';
|
|
394
|
+
}
|
|
395
|
+
return set.filesProcessed ? 'ok' : 'zero-files';
|
|
396
|
+
}
|
|
382
397
|
async defaultRunProject(spec) {
|
|
383
398
|
const startedAt = Date.now();
|
|
384
399
|
// Per-target scope: az EXPLICIT `spec.scopePath` nyer (heterogén „scan-all"-hoz, pl. a memóriám root-szintű
|
|
@@ -401,11 +416,43 @@ class FAM_ScanJob_ControlService {
|
|
|
401
416
|
exclude: spec.exclude,
|
|
402
417
|
},
|
|
403
418
|
};
|
|
419
|
+
// ELO-ELLENORZES (2026-08-22, mert lelet): a heti re-scan HAROM egymast koveto heten (aug 3/10/17) NEMAN
|
|
420
|
+
// bukott a `documentations` / `OGS-projects\documents` mappakra — azokat atneveztek (`fdp-documentations` /
|
|
421
|
+
// `ogs-documents`), de a job-lista a REGI utvonalat vitte tovabb. A `defaultRunProject` viszont feltetel nelkul
|
|
422
|
+
// `ok`-ot adott vissza, ezert a job `53/53 ok`-kent zarult, es a FAM ket honapig a JUNIUSI doktrinat szolgalta ki
|
|
423
|
+
// ugy, hogy azt senki nem lathatta. A nem letezo cel-utvonal ezentul HANGOS hiba, nem zold pipa.
|
|
424
|
+
if (FAM_ScanJob_ControlService.classifyTargetOutcome({ pathExists: (0, fs_1.existsSync)(spec.path) }) === 'missing-path') {
|
|
425
|
+
return {
|
|
426
|
+
project: spec.project, path: spec.path, status: 'error',
|
|
427
|
+
seconds: Math.round((Date.now() - startedAt) / 1000),
|
|
428
|
+
error: {
|
|
429
|
+
message: `A scan cel-utvonala NEM LETEZIK: '${spec.path}'. A mappat valoszinuleg atneveztek vagy `
|
|
430
|
+
+ 'athelyeztek — javitsd a scan-job cel-listajat, kulonben ez a forras NEMAN elavul.',
|
|
431
|
+
},
|
|
432
|
+
};
|
|
433
|
+
}
|
|
404
434
|
try {
|
|
405
435
|
const output = await fam_operation_queue_service_1.FAM_OperationQueue_Service.getInstance()
|
|
406
436
|
.enqueue(() => fam_write_tool_service_1.FAM_WriteTool_Service.getInstance().handle(input));
|
|
407
437
|
const scan = output.scan;
|
|
408
438
|
const verdicts = scan?.verdicts;
|
|
439
|
+
// NULLA feldolgozott fajl letezo utvonalon: a cel nem jarult hozza az indexhez (rossz include/exclude,
|
|
440
|
+
// ures mappa vagy tul ago ignore-minta). Ez NEM siker — kulonben ugyanaz a nema elavulas all elo, csak
|
|
441
|
+
// mas okbol. Hangos hiba, hogy a heti riport ranezesre megmutassa.
|
|
442
|
+
const outcome = FAM_ScanJob_ControlService.classifyTargetOutcome({
|
|
443
|
+
pathExists: true, filesProcessed: scan?.filesProcessed,
|
|
444
|
+
});
|
|
445
|
+
if (outcome === 'zero-files') {
|
|
446
|
+
return {
|
|
447
|
+
project: spec.project, path: spec.path, status: 'error',
|
|
448
|
+
filesProcessed: 0, chunks: scan?.chunks, verdicts: verdicts,
|
|
449
|
+
seconds: Math.round((Date.now() - startedAt) / 1000),
|
|
450
|
+
error: {
|
|
451
|
+
message: `A scan NULLA fajlt dolgozott fel a letezo '${spec.path}' utvonalon — a cel nem `
|
|
452
|
+
+ 'jarult hozza az indexhez (ellenorizd az include/exclude + .famignore mintakat).',
|
|
453
|
+
},
|
|
454
|
+
};
|
|
455
|
+
}
|
|
409
456
|
return {
|
|
410
457
|
project: spec.project, path: spec.path, status: 'ok',
|
|
411
458
|
filesProcessed: scan?.filesProcessed, chunks: scan?.chunks, verdicts: verdicts,
|
|
@@ -33,7 +33,10 @@ class FAM_ReadResponseShape_Util {
|
|
|
33
33
|
table: hit.table,
|
|
34
34
|
// ÚTVONAL-SSOT: a `sourceFilePath` már a hívó `basePath`-jához igazított (rebaseToBasePath), különben az
|
|
35
35
|
// abszolút út — így MINDIG feloldható. A régi mezőket lentebb megtartjuk (kompatibilitás).
|
|
36
|
-
|
|
36
|
+
// Ha nincs fájl-forrás (API-n írt bejegyzés: manual/agent write), a `path` NEM maradhat néma `null` —
|
|
37
|
+
// az az agentnek zsákutca („itt egy találat, de nem tudom, hol van"). Helyette LOCATOR-t adunk, amivel
|
|
38
|
+
// a bejegyzés visszakereshető: `fam:<tár>/<id>` (2026-08-14 elő-próbálgatás lelete).
|
|
39
|
+
path: hit.sourceFilePath ?? hit.absolutePath ?? `fam:${hit.table}/${hit.id}`,
|
|
37
40
|
score: round(hit.score),
|
|
38
41
|
finalScore: round(hit.finalScore),
|
|
39
42
|
};
|
|
@@ -124,12 +127,24 @@ class FAM_ReadResponseShape_Util {
|
|
|
124
127
|
+ 'a javasolt út — a chat-választ nem terheli).');
|
|
125
128
|
}
|
|
126
129
|
if (set.totalRelevant > set.shown * 3 && !set.hasScopeFilter) {
|
|
127
|
-
hints.push('CÉLZOTTABBAN: szűkíts `scope`-pal (pl. `{"layer":"project","
|
|
130
|
+
hints.push('CÉLZOTTABBAN: szűkíts `scope`-pal (pl. `{"layer":"project","rawName":"<projekt>"}`), `tags`-szel '
|
|
128
131
|
+ 'vagy `kind`-dal — a sok találat általában túl tág kérdést jelez.');
|
|
129
132
|
}
|
|
130
133
|
if (!set.totalRelevant) {
|
|
131
|
-
|
|
132
|
-
|
|
134
|
+
// SZŰRŐ-SPECIFIKUS diagnózis (2026-08-14 battery-lelet): ha VAN aktív szűrő és NULLA a találat, akkor
|
|
135
|
+
// nagy eséllyel a SZŰRŐ ölte meg a keresést, nem a query. Korábban ilyenkor is azt tanácsoltuk, hogy
|
|
136
|
+
// „próbálj más megfogalmazást" — ez FÉLREVEZETŐ volt (mérve: ugyanaz a query szűrő nélkül 5 találatot
|
|
137
|
+
// adott). Az agentet a TÉNYLEGES okhoz kell terelni.
|
|
138
|
+
if (set.hasScopeFilter && !set.shown) {
|
|
139
|
+
hints.push('NULLA találat AKTÍV SZŰRŐVEL — nagy eséllyel a szűrő a szűk keresztmetszet, nem a kérdés. '
|
|
140
|
+
+ 'Próbáld a query-t szűrő NÉLKÜL (`scopeFilter`/`tagFilter`/`kindFilter` elhagyásával); ha úgy '
|
|
141
|
+
+ 'vannak találatok, a szűrő értéke hibás vagy nem létezik (a `tags`/`kind` szabad szövegűek, a '
|
|
142
|
+
+ 'scope-hoz a `{"layer":"…","rawName":"…"}` alak kell).');
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
hints.push('NINCS magabiztos találat: próbálj más megfogalmazást/kulcsszavakat, vagy emeld a `topK`-t; '
|
|
146
|
+
+ 'a `minScore: 0` a leggyengébb tippeket is visszaadja.');
|
|
147
|
+
}
|
|
133
148
|
}
|
|
134
149
|
return hints;
|
|
135
150
|
}
|
|
@@ -237,7 +237,10 @@ class FAM_ReadTool_Service {
|
|
|
237
237
|
});
|
|
238
238
|
}
|
|
239
239
|
for (const query of input.queries) {
|
|
240
|
-
|
|
240
|
+
// A `.trim()` SZANDEKOS (2026-08-22 robusztussag-lelet): a puszta `!query.query` csak az URES stringet
|
|
241
|
+
// fogta meg, ezert a csupa-szokoz query ATMENT a validacion, es a vektor-kereses ertelmetlen zajt adott
|
|
242
|
+
// vissza (egy meresen ~13k token egyetlen ertelmetlen keresesre).
|
|
243
|
+
if (!query || !Array.isArray(query.tables) || !query.tables.length || !query.query?.trim()) {
|
|
241
244
|
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
242
245
|
errorCode: error_codes_const_1.FAM_ERROR_CODES.valReadEmptyOrReference,
|
|
243
246
|
message: 'Minden `read` query-nek legalább 1 `tables` elemet és egy nem-üres `query` '
|
|
@@ -246,6 +249,44 @@ class FAM_ReadTool_Service {
|
|
|
246
249
|
context: { operation: 'read-validate' },
|
|
247
250
|
});
|
|
248
251
|
}
|
|
252
|
+
// ISMERETLEN TÁR (2026-08-14 battery-lelet): eddig egy ELGÉPELT tárnév NÉMÁN 0 találatot adott (HTTP 200)
|
|
253
|
+
// — az agent ebből azt a HAMIS következtetést vonja le, hogy „nincs ilyen tudás". Ez a legrosszabb hiba-fajta:
|
|
254
|
+
// csendes, téves válasz. Mostantól EXPLICIT hiba, a MEGENGEDETT tárak felsorolásával.
|
|
255
|
+
const known = Object.values(fam_table_type_enum_1.FAM_Table);
|
|
256
|
+
const unknown = query.tables.filter((table) => !known.includes(table));
|
|
257
|
+
if (unknown.length) {
|
|
258
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
259
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.valReadEmptyOrReference,
|
|
260
|
+
message: `Ismeretlen tár: ${unknown.map((t) => `'${t}'`).join(', ')}. `
|
|
261
|
+
+ `Megengedett: ${known.filter((t) => t !== fam_table_type_enum_1.FAM_Table.reference).join(' | ')}. `
|
|
262
|
+
+ '(Elgépelés? A `capabilities` action:"list" felsorolja a tárakat és a pontos sémákat.)',
|
|
263
|
+
issuer: this.issuer,
|
|
264
|
+
context: { operation: 'read-validate' },
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
// topK/minScore TARTOMÁNY (2026-08-14 battery-lelet): a `topK: -5` eddig egy NYERS TypeError-t okozott
|
|
268
|
+
// (`Cannot read properties of undefined (reading 'finalScore')`) — kezeletlen összeomlás, kriptikus üzenettel.
|
|
269
|
+
// A FELSO hatar is ELLENORZOTT (2026-08-22): a hibauzenet eddig is „1 es 200 kozotti" erteket igert, de a
|
|
270
|
+
// kod a `topK: 10000`-t elfogadta — a szerzodes es a viselkedes szetcsuszott, es a hivo context-bombat kapott.
|
|
271
|
+
if (query.topK !== undefined
|
|
272
|
+
&& (!Number.isFinite(query.topK) || query.topK < 1 || query.topK > retrieval_1.MAX_PAGE_SIZE)) {
|
|
273
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
274
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.valReadEmptyOrReference,
|
|
275
|
+
message: `A \`topK\` 1 és ${retrieval_1.MAX_PAGE_SIZE} közötti egész szám kell legyen `
|
|
276
|
+
+ `(kapott: ${String(query.topK)}). Hagyd el a mezőt a tár-alapú default-hoz.`,
|
|
277
|
+
issuer: this.issuer,
|
|
278
|
+
context: { operation: 'read-validate' },
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
if (query.minScore !== undefined && (!Number.isFinite(query.minScore) || query.minScore < 0 || query.minScore > 1)) {
|
|
282
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
283
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.valReadEmptyOrReference,
|
|
284
|
+
message: `A \`minScore\` 0 és 1 közötti szám kell legyen (kapott: ${String(query.minScore)}) — `
|
|
285
|
+
+ 'ez a NYERS koszinusz-küszöb. `0` = mindent visszaad (best-effort recall).',
|
|
286
|
+
issuer: this.issuer,
|
|
287
|
+
context: { operation: 'read-validate' },
|
|
288
|
+
});
|
|
289
|
+
}
|
|
249
290
|
if (query.tables.includes(fam_table_type_enum_1.FAM_Table.reference)) {
|
|
250
291
|
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
251
292
|
errorCode: error_codes_const_1.FAM_ERROR_CODES.valReadEmptyOrReference,
|
|
@@ -278,6 +319,8 @@ class FAM_ReadTool_Service {
|
|
|
278
319
|
kindFilter: query.kindFilter,
|
|
279
320
|
excludeIds: query.excludeIds,
|
|
280
321
|
depth: query.depth,
|
|
322
|
+
// Per-query tartalom-kapcsolo atvezetese (2026-08-14 lelet: eddig itt VESZETT EL).
|
|
323
|
+
includeContent: query.includeContent,
|
|
281
324
|
};
|
|
282
325
|
}
|
|
283
326
|
}
|
|
@@ -163,6 +163,29 @@ class FAM_WriteTool_Service {
|
|
|
163
163
|
context: { operation: 'write-validate', table: input.table },
|
|
164
164
|
});
|
|
165
165
|
}
|
|
166
|
+
// WEIGHT / IMPORTANCE TARTOMANY (2026-08-22 robusztussag-meres): a `weight: -5` eddig NEMAN atment
|
|
167
|
+
// (`warnings: []`), es a bejegyzes ezzel VEGLEG visszakereshetetlenne valt — a `finalScore = score x weight`
|
|
168
|
+
// negativba fordul, igy a talalat SOHA nem rangsorolhat, meg a sajat egyedi markerere + tagjere sem. Az agent
|
|
169
|
+
// ebbol azt latja, hogy „az iras sikerult, de a tartalom nincs meg" — a legrosszabb fajta nema adatvesztes.
|
|
170
|
+
if (input.weight !== undefined && (!Number.isFinite(input.weight) || input.weight <= 0)) {
|
|
171
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
172
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.valWriteMissingField,
|
|
173
|
+
message: `A \`weight\` POZITIV szam kell legyen (kapott: ${String(input.weight)}). A rangsor `
|
|
174
|
+
+ '`score x weight` szorzat, ezert a 0 vagy negativ suly a bejegyzest VEGLEG '
|
|
175
|
+
+ 'visszakereshetetlenne teszi. Alap: 1 (coding_patterns: 5).',
|
|
176
|
+
issuer: this.issuer,
|
|
177
|
+
context: { operation: 'write-validate', table: input.table },
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
if (input.importance !== undefined
|
|
181
|
+
&& (!Number.isFinite(input.importance) || input.importance < 0 || input.importance > 1)) {
|
|
182
|
+
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
183
|
+
errorCode: error_codes_const_1.FAM_ERROR_CODES.valWriteMissingField,
|
|
184
|
+
message: `Az \`importance\` 0 es 1 kozotti szam kell legyen (kapott: ${String(input.importance)}).`,
|
|
185
|
+
issuer: this.issuer,
|
|
186
|
+
context: { operation: 'write-validate', table: input.table },
|
|
187
|
+
});
|
|
188
|
+
}
|
|
166
189
|
const needsTarget = input.operation === fam_mcp_interface_1.FAM_WriteOperation.update || input.operation === fam_mcp_interface_1.FAM_WriteOperation.delete;
|
|
167
190
|
if (needsTarget && (!input.target || !input.target.by || !input.target.value)) {
|
|
168
191
|
throw fam_error_factory_util_1.FAM_Error_Util.create({
|
|
@@ -24,19 +24,44 @@ class FAM_LexicalMatch_Util {
|
|
|
24
24
|
'az', 'és', 'es', 'hogy', 'van', 'egy', 'nem', 'igen', 'de', 'mert', 'ami', 'amit', 'ez', 'azt', 'volt',
|
|
25
25
|
'lesz', 'kell', 'meg', 'el', 'be', 'ki', 'le', 'fel', 'rá', 'ra', 'mi', 'te', 'ő', 'mit', 'hol',
|
|
26
26
|
]);
|
|
27
|
+
/** A magyar ragok HOSSZ szerint csökkenő sorrendben (a leghosszabb egyezés nyer — `-ból` előbb, mint `-ó`). */
|
|
28
|
+
static HU_SUFFIXES = [
|
|
29
|
+
'ban', 'ben', 'ból', 'ből', 'nak', 'nek', 'val', 'vel', 'hoz', 'hez', 'höz', 'ról', 'ről', 'tól', 'től',
|
|
30
|
+
'ot', 'et', 'öt', 'at', 'ok', 'ek', 'ök', 'ak', 'ra', 're', 'ig', 'ba', 'be', 'on', 'en', 'ön', 'an',
|
|
31
|
+
];
|
|
32
|
+
/** A tő MINIMÁLIS hossza tövezés után (a túl-tövezés hamis egyezéseket hozna). */
|
|
33
|
+
static MIN_STEM_LEN = 4;
|
|
27
34
|
/** Tokenizálás: kisbetűsít, nem-alfanumerikuson tör, stopword + rövid token kihagyva, DEDUP (Set). */
|
|
28
35
|
static tokenize(text) {
|
|
29
36
|
const terms = new Set();
|
|
30
37
|
if (!text) {
|
|
31
38
|
return terms;
|
|
32
39
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
40
|
+
// ÉKEZET-JAVÍTÁS (2026-08-14 lelet): a korábbi `[^a-z0-9]+` split a magyar ékezetes betűket ELVÁLASZTÓNAK
|
|
41
|
+
// vette, ezért minden ékezetes szó SZÉTESETT („szabály" → „szab" + „ly", „mérés" → „m" + „r" + „s").
|
|
42
|
+
// Így a magyar query-k lexikai jele gyakorlatilag ELVESZETT.
|
|
43
|
+
for (const raw of text.toLowerCase().split(/[^a-z0-9áéíóöőúüű]+/)) {
|
|
44
|
+
if (raw.length < FAM_LexicalMatch_Util.MIN_TOKEN_LEN || FAM_LexicalMatch_Util.STOPWORDS.has(raw)) {
|
|
45
|
+
continue;
|
|
36
46
|
}
|
|
47
|
+
terms.add(raw);
|
|
37
48
|
}
|
|
38
49
|
return terms;
|
|
39
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Magyar toldalék levágása (PURE) — a tő, ha a levágás UTÁN is értelmes hosszúságú marad, különben `undefined`.
|
|
53
|
+
* A leggyakoribb rag-osztályok: tárgyeset (`-t`/`-ot`/`-et`/`-öt`/`-at`), többes (`-ok`/`-ek`/`-ök`/`-ak`),
|
|
54
|
+
* hely-/eszközhatározók (`-ban`/`-ben`/`-ból`/`-ből`/`-ra`/`-re`/`-val`/`-vel`/`-nak`/`-nek`/`-hoz`/`-hez`/`-ig`).
|
|
55
|
+
* A `MIN_STEM_LEN` védi a túl-tövezéstől (pl. `este` → `est` nem keletkezik hamis egyezésként).
|
|
56
|
+
*/
|
|
57
|
+
static stripHungarianSuffix(token) {
|
|
58
|
+
for (const suffix of FAM_LexicalMatch_Util.HU_SUFFIXES) {
|
|
59
|
+
if (token.length - suffix.length >= FAM_LexicalMatch_Util.MIN_STEM_LEN && token.endsWith(suffix)) {
|
|
60
|
+
return token.slice(0, token.length - suffix.length);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
40
65
|
/**
|
|
41
66
|
* Lexikai átfedés-score (0..1): a `queryTerms` hányad része van jelen az entry kereshető szövegében.
|
|
42
67
|
* `content`-egyezés = base-átfedés; `headingPath`/`sourceFilePath`-egyezés = + `TITLE_PATH_BONUS` súly (1-re vágva).
|
|
@@ -52,8 +77,14 @@ class FAM_LexicalMatch_Util {
|
|
|
52
77
|
let baseMatched = 0;
|
|
53
78
|
let titleMatched = 0;
|
|
54
79
|
for (const term of queryTerms) {
|
|
55
|
-
|
|
56
|
-
|
|
80
|
+
// MAGYAR TOLDALÉK-ILLESZTÉS (2026-08-14): a magyar az ANGOL szakszavakat is ragozza („loopot",
|
|
81
|
+
// „scriptet", „branchról"), így a nyers `loopot` SOHA nem egyezett a dokumentum `loop` szavával — mérve:
|
|
82
|
+
// a „mikor kell review loopot futtatni" query 5 tokenjéből EGY egyezett. A tő ILLESZTÉSI SEGÉD, NEM külön
|
|
83
|
+
// query-term: nem növeli a nevezőt (különben az angol szavak téves tövezése — `convention` → `conventi` —
|
|
84
|
+
// HÍGÍTANÁ a score-t), csak egy MÁSODIK esélyt ad ugyanannak a tokennek az egyezésre.
|
|
85
|
+
const stem = FAM_LexicalMatch_Util.stripHungarianSuffix(term);
|
|
86
|
+
const inTitlePath = titlePathTerms.has(term) || (!!stem && titlePathTerms.has(stem));
|
|
87
|
+
if (contentTerms.has(term) || (!!stem && contentTerms.has(stem)) || inTitlePath) {
|
|
57
88
|
baseMatched++;
|
|
58
89
|
}
|
|
59
90
|
if (inTitlePath) {
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FAM_ResultDiversity_Util = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* `FAM_ResultDiversity_Util` — a visszaadott top-K **információ-sűrűségét** védi. Két MÉRT hibát javít
|
|
6
|
+
* (dogfood-mérés, 2026-08-22):
|
|
7
|
+
*
|
|
8
|
+
* 1. **Chunk-elárasztás:** a top-K slotok **44%-a** (11/25 mérve) UGYANANNAK a fájlnak egy másik chunkja volt —
|
|
9
|
+
* a „polling tilalom" query-nél a TELJES top-5 EGYETLEN fájl darabjaiból állt. Az agent így egy dokumentumot
|
|
10
|
+
* kap ötször, öt különböző válasz-jelölt helyett.
|
|
11
|
+
* 2. **Tár-temetés:** több-táras query-ben a `rules` **0/3** arányban tűnt el a `documents` mögött (kontrollált
|
|
12
|
+
* mérés: ugyanaz a query csak-`rules`-szal AZONNAL hozta a kanonikus szabályt) — a bőbeszédűbb tár egyszerűen
|
|
13
|
+
* kiszorítja a tömörebbet, és az agent azt hiszi, nincs rá szabály.
|
|
14
|
+
*
|
|
15
|
+
* **Sosem DOBUNK el találatot** (a recall szent): a levágott chunkok a lista VÉGÉRE kerülnek (demote, nem drop),
|
|
16
|
+
* így a `totalRelevant` és a `truncated` statisztika érintetlen marad. A `pinned` (kód-exact citáció) hitek
|
|
17
|
+
* mozdíthatatlanok — az F3-1 garancia elsőbbséget élvez a diverzitással szemben.
|
|
18
|
+
*/
|
|
19
|
+
class FAM_ResultDiversity_Util {
|
|
20
|
+
/** Legfeljebb ennyi promóciót engedünk a tár-kvótának, hogy a rangsor ne forduljon fel (window fele). */
|
|
21
|
+
static MAX_PROMOTION_RATIO = 0.5;
|
|
22
|
+
/**
|
|
23
|
+
* A fájl-identitás kulcsa. A scan-chunkok `absolutePath`-ja a kanonikus kulcs; ha nincs (memory/knowledge
|
|
24
|
+
* bejegyzés, ami nem fájlból jött), akkor az `id` — így minden ilyen entry EGYEDI marad, és a chunk-collapse
|
|
25
|
+
* nem nyúl hozzájuk (nincs mit összevonni).
|
|
26
|
+
*/
|
|
27
|
+
static fileKey(hit) {
|
|
28
|
+
return hit.absolutePath || hit.sourceFilePath || `id:${hit.id}`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Diverzifikálja a RENDEZETT találati listát: (a) fájlonként legfeljebb `maxChunksPerFile` chunk kerül előre,
|
|
32
|
+
* (b) minden kért tár, amelynek VAN találata, kap legalább `tableMinShare` helyet az első `windowSize`-ban.
|
|
33
|
+
* A `pinned` hitek sorrendje és tagsága garantáltan változatlan.
|
|
34
|
+
*/
|
|
35
|
+
static diversify(set) {
|
|
36
|
+
const pinned = set.isPinned || (() => false);
|
|
37
|
+
if (set.hits.length <= 1) {
|
|
38
|
+
return set.hits;
|
|
39
|
+
}
|
|
40
|
+
const collapsed = this.collapseChunks(set.hits, set.maxChunksPerFile, pinned);
|
|
41
|
+
return this.enforceTableShare(collapsed, set.tableMinShare, set.windowSize, pinned);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* (a) Chunk-collapse: fájlonként az első `max` chunk marad a helyén, a többi a lista végére csúszik. `max <= 0`
|
|
45
|
+
* → kikapcsolva (a hívó config-ból tilthatja).
|
|
46
|
+
*/
|
|
47
|
+
static collapseChunks(hits, max, pinned) {
|
|
48
|
+
if (max <= 0) {
|
|
49
|
+
return hits;
|
|
50
|
+
}
|
|
51
|
+
const kept = [];
|
|
52
|
+
const demoted = [];
|
|
53
|
+
const perFile = new Map();
|
|
54
|
+
for (const hit of hits) {
|
|
55
|
+
// A kód-exact citáció (F3-1) MINDIG marad — a determinisztikus garancia erősebb a diverzitásnál.
|
|
56
|
+
if (pinned(hit)) {
|
|
57
|
+
kept.push(hit);
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const key = this.fileKey(hit);
|
|
61
|
+
const seen = perFile.get(key) || 0;
|
|
62
|
+
if (seen < max) {
|
|
63
|
+
perFile.set(key, seen + 1);
|
|
64
|
+
kept.push(hit);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
demoted.push(hit);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return kept.concat(demoted);
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* (b) Tár-kvóta: ha egy kért tárnak van találata, de az első `windowSize`-ban kevesebb, mint `minShare`, akkor a
|
|
74
|
+
* legjobb helyezésű ilyen találatát ELŐRE hozzuk a window UTOLSÓ (nem-pinned) helyére — minimális bolygatással,
|
|
75
|
+
* a kiszorult elem eggyel hátrébb csúszik (nem esik ki a listából).
|
|
76
|
+
*/
|
|
77
|
+
static enforceTableShare(hits, minShare, windowSize, pinned) {
|
|
78
|
+
if (minShare <= 0 || windowSize <= 0 || hits.length <= windowSize) {
|
|
79
|
+
return hits;
|
|
80
|
+
}
|
|
81
|
+
const result = hits.slice();
|
|
82
|
+
const maxPromotions = Math.max(1, Math.floor(windowSize * this.MAX_PROMOTION_RATIO));
|
|
83
|
+
let promotions = 0;
|
|
84
|
+
// A tárak sorrendje a LEGJOBB helyezésük szerint — a leginkább „majdnem befért" tár kap előbb kvótát.
|
|
85
|
+
for (const table of this.tablesByBestRank(result)) {
|
|
86
|
+
if (promotions >= maxPromotions) {
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
const inWindow = result.slice(0, windowSize).filter((hit) => hit.table === table).length;
|
|
90
|
+
if (inWindow >= minShare) {
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
const donorIndex = result.findIndex((hit, index) => index >= windowSize && hit.table === table);
|
|
94
|
+
if (donorIndex < 0) {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
// A window utolsó NEM-pinned helye a beszúrási pont; ha minden hely pinned, nem bolygatunk.
|
|
98
|
+
const slot = this.lastUnpinnedSlot(result, windowSize, pinned);
|
|
99
|
+
if (slot < 0) {
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
const [promoted] = result.splice(donorIndex, 1);
|
|
103
|
+
result.splice(slot, 0, promoted);
|
|
104
|
+
promotions++;
|
|
105
|
+
}
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
/** A találati listában szereplő tárak, a LEGJOBB (legkisebb indexű) helyezésük szerint rendezve. */
|
|
109
|
+
static tablesByBestRank(hits) {
|
|
110
|
+
const bestRank = new Map();
|
|
111
|
+
hits.forEach((hit, index) => {
|
|
112
|
+
if (!bestRank.has(hit.table)) {
|
|
113
|
+
bestRank.set(hit.table, index);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
return Array.from(bestRank.entries()).sort((a, b) => a[1] - b[1]).map((entry) => entry[0]);
|
|
117
|
+
}
|
|
118
|
+
/** A window utolsó nem-pinned indexe (ide szúrjuk a promótált hitet), vagy `-1` ha minden hely pinned. */
|
|
119
|
+
static lastUnpinnedSlot(hits, windowSize, pinned) {
|
|
120
|
+
for (let index = windowSize - 1; index >= 0; index--) {
|
|
121
|
+
if (!pinned(hits[index])) {
|
|
122
|
+
return index;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return -1;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
exports.FAM_ResultDiversity_Util = FAM_ResultDiversity_Util;
|
|
@@ -14,6 +14,8 @@ const TAG_FREQUENCY_RATIO = 0.4;
|
|
|
14
14
|
* feltételhez kötött (graceful: a hiányzó statisztikájú javaslat KIMARAD, nem hiba — dsgn-005 §kockázat).
|
|
15
15
|
*/
|
|
16
16
|
class FAM_RetrievalSuggestions_Util {
|
|
17
|
+
/** A topK-javaslat abszolut plafonja — e folott a javaslat kontextus-bombava valik (2026-08-22 meres). */
|
|
18
|
+
static SUGGEST_TOPK_CAP = 25;
|
|
17
19
|
/**
|
|
18
20
|
* A teljes, rendezett javaslat-lista (dsgn-005 §4.4). A sorrend kötött (scope → tag → minScore →
|
|
19
21
|
* topK → kind). Üres relevantSet → `[]`. A scope/tag/kind a relevantSet eloszlásából; a minScore a
|
|
@@ -147,8 +149,18 @@ class FAM_RetrievalSuggestions_Util {
|
|
|
147
149
|
return undefined;
|
|
148
150
|
}
|
|
149
151
|
const totalRelevant = input.relevantSet.length;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
+
// MERSEKELT lepes, NEM „hozd be az egeszet" (2026-08-22, negy fuggetlen agent-meres): a javaslat korabban a
|
|
153
|
+
// teljes relevans halmazt ajanlotta (merve: `topK: 859`, `906`, `674`), ami (a) kontextus-bomba — egy agent a
|
|
154
|
+
// tanacsot kovetve tobb tizezer tokent egetett el —, es (b) TELJESITHETETLEN: a `topK: 859` valojaban 77
|
|
155
|
+
// talalatot adott, mire a valasz a hivo `topK`-jat okolta a vagasert. Ezert: legfeljebb a jelenlegi ablak
|
|
156
|
+
// haromszorosa, `SUGGEST_TOPK_CAP`-re vagva, es a content-kikapcsolas tanacsaval egyutt.
|
|
157
|
+
const step = Math.min(totalRelevant, Math.max(input.effectiveTopK * 3, input.effectiveTopK + 1), FAM_RetrievalSuggestions_Util.SUGGEST_TOPK_CAP, input.maxPageSize);
|
|
158
|
+
if (step <= input.effectiveTopK) {
|
|
159
|
+
return undefined;
|
|
160
|
+
}
|
|
161
|
+
return `emeld a topK-t ${step}-re a kovetkezo adagert (a kuszob felett osszesen ${totalRelevant} elem van — `
|
|
162
|
+
+ 'ezt NE probald egyben lekerni; ha tobb kell, lapozz tovabb, es tartsd `includeContent: false`-on, '
|
|
163
|
+
+ 'amig ki nem valasztottad, melyik talalat kell tartalommal)';
|
|
152
164
|
}
|
|
153
165
|
/**
|
|
154
166
|
* kindFilter-javaslat (dsgn-005 §4.4 #5): csak ha a relevantSet ≥2 különböző `kind`-ot tartalmaz
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.FAM_Retrieval_ControlService = void 0;
|
|
3
|
+
exports.FAM_Retrieval_ControlService = exports.MAX_PAGE_SIZE = void 0;
|
|
4
4
|
const fam_table_type_enum_1 = require("../../../_enums/fam-table.type-enum");
|
|
5
5
|
const fam_reference_code_util_1 = require("../../../_collections/fam-reference-code.util");
|
|
6
6
|
const config_control_service_1 = require("../../../_routes/server/config/config.control-service");
|
|
@@ -10,10 +10,11 @@ const fam_retrieval_candidate_data_service_1 = require("./fam-retrieval-candidat
|
|
|
10
10
|
const fam_retrieval_suggestions_util_1 = require("./fam-retrieval-suggestions.util");
|
|
11
11
|
const fam_memory_activation_util_1 = require("../_collections/fam-memory-activation.util");
|
|
12
12
|
const fam_lexical_match_util_1 = require("../_collections/fam-lexical-match.util");
|
|
13
|
+
const fam_result_diversity_util_1 = require("../_collections/fam-result-diversity.util");
|
|
13
14
|
const fam_memory_reactivation_control_service_1 = require("./fam-memory-reactivation.control-service");
|
|
14
15
|
const fam_memory_cold_search_control_service_1 = require("./fam-memory-cold-search.control-service");
|
|
15
16
|
/** A topK / lapozás abszolút plafonja (CCAP MAX_PAGE_SIZE=500; dsgn-005 §6). */
|
|
16
|
-
|
|
17
|
+
exports.MAX_PAGE_SIZE = 500;
|
|
17
18
|
/**
|
|
18
19
|
* `FAM_Retrieval_ControlService` (MP-5, dsgn-005) — a `read` **egylépcsős** retrieval-pipeline ENGINE-je.
|
|
19
20
|
* Singleton. Egy hívás több táblát + több query-t kezel; minden query ÖNÁLLÓ, kötött-sorrendű
|
|
@@ -60,7 +61,10 @@ class FAM_Retrieval_ControlService {
|
|
|
60
61
|
async read(request) {
|
|
61
62
|
const includeContent = request.includeContent !== false;
|
|
62
63
|
// Per-query párhuzamosítható pipeline-ok (egymástól függetlenek; dsgn-005 §2).
|
|
63
|
-
const results = await Promise.all(
|
|
64
|
+
const results = await Promise.all(
|
|
65
|
+
// A QUERY sajat `includeContent`-je NYER a request-szintu felett (2026-08-14 lelet: eddig a query-szintu
|
|
66
|
+
// ertek nemán elnyelodott, ezert a „kompakt lista" szandeku hivas teljes tartalmat adott vissza).
|
|
67
|
+
request.queries.map((query) => this.runQuery(query, query.includeContent !== undefined ? query.includeContent !== false : includeContent, request.globalScopeFilter)));
|
|
64
68
|
return { results: results };
|
|
65
69
|
}
|
|
66
70
|
/**
|
|
@@ -80,7 +84,9 @@ class FAM_Retrieval_ControlService {
|
|
|
80
84
|
const queryVector = await this.embedQuery(query.query, primaryTable);
|
|
81
85
|
// ②–④ per-tár: Mongo-prefilter → vektor-keresés a szűkített poolon → hit-row összefűzés.
|
|
82
86
|
const allHits = [];
|
|
83
|
-
|
|
87
|
+
// TÁR-DEDUP (2026-08-14 battery-lelet): a `tables:['rules','rules']` KÉTSZER futtatta ugyanazt a keresést
|
|
88
|
+
// (mérve: 1036ms vs 558ms) — azonos eredményért dupla vektor-munka. A dedup után a hívó hibája ingyenes.
|
|
89
|
+
for (const table of Array.from(new Set(query.tables))) {
|
|
84
90
|
const tableHits = await this.searchTable({ table, query, queryVector, scopeExpand, config, includeContent });
|
|
85
91
|
allHits.push(...tableHits);
|
|
86
92
|
}
|
|
@@ -270,7 +276,7 @@ class FAM_Retrieval_ControlService {
|
|
|
270
276
|
vectorHits = await embedding_1.FAM_VectorSearch_ControlService.getInstance().search({
|
|
271
277
|
table: set.table,
|
|
272
278
|
queryVector: set.queryVector,
|
|
273
|
-
topK: MAX_PAGE_SIZE,
|
|
279
|
+
topK: exports.MAX_PAGE_SIZE,
|
|
274
280
|
});
|
|
275
281
|
if (!vectorHits.length) {
|
|
276
282
|
return [];
|
|
@@ -306,7 +312,7 @@ class FAM_Retrieval_ControlService {
|
|
|
306
312
|
table: set.table,
|
|
307
313
|
queryVector: set.queryVector,
|
|
308
314
|
candidateIds: candidateIds,
|
|
309
|
-
topK: Math.min(candidateIds.length, MAX_PAGE_SIZE),
|
|
315
|
+
topK: Math.min(candidateIds.length, exports.MAX_PAGE_SIZE),
|
|
310
316
|
});
|
|
311
317
|
}
|
|
312
318
|
// ⑤ weight-szorzó: finalScore = score × (weight ?? 1); weight ≤ 0 → kizárt (nem kerül a hits közé).
|
|
@@ -408,11 +414,13 @@ class FAM_Retrieval_ControlService {
|
|
|
408
414
|
* → tiszta relevancia-rangsor; az identity-query-ken a summary a MAGAS cosine miatt így is felszínre kerül. Minden
|
|
409
415
|
* NEM-scan-summary source érintetlen (×1). READ-time, a nyers `score` (relevancia) változatlan.
|
|
410
416
|
*/
|
|
411
|
-
scanSummaryFactor(source,
|
|
412
|
-
|
|
417
|
+
scanSummaryFactor(source, effective, scanSummaryWeight) {
|
|
418
|
+
// FONTOS (2026-08-14): a cap a TEMPERÁLT (effektív) súlyra vonatkozik, nem a nyersre — különben a
|
|
419
|
+
// `effectiveWeight` és a cap KÉTSZER vonná le ugyanazt (mérve: w3 → 1.24 × 0.333 = 0.41 a kívánt 1.0 helyett).
|
|
420
|
+
if (source?.type !== 'scan-summary' || effective <= scanSummaryWeight) {
|
|
413
421
|
return 1;
|
|
414
422
|
}
|
|
415
|
-
return scanSummaryWeight /
|
|
423
|
+
return scanSummaryWeight / effective;
|
|
416
424
|
}
|
|
417
425
|
/**
|
|
418
426
|
* Memory Activation Model decay-szorzó (dsgn-013 §3) — CSAK a `memory` táron, ha engedélyezett. A frissen/gyakran
|
|
@@ -453,7 +461,7 @@ class FAM_Retrieval_ControlService {
|
|
|
453
461
|
// finalScore = score × weight × chunkF × sourceF × decayF × (1 + keywordWeight × lexicalScore).
|
|
454
462
|
const chunkFactor = this.chunkTypeFactor(set.entry.chunkType, set.importChunkWeight);
|
|
455
463
|
const sourceFactor = this.importSourceFactor(set.entry.source, set.importSourceWeight);
|
|
456
|
-
const summaryFactor = this.scanSummaryFactor(set.entry.source, set.weight, set.config.scanSummaryWeight);
|
|
464
|
+
const summaryFactor = this.scanSummaryFactor(set.entry.source, FAM_Retrieval_ControlService.effectiveWeight(set.weight, set.config.weightInfluence), set.config.scanSummaryWeight);
|
|
457
465
|
const decayFactor = this.memoryDecayFactor(set.entry, set.table, set.config, set.nowMs);
|
|
458
466
|
const lexicalScore = set.config.keywordWeight > 0
|
|
459
467
|
? fam_lexical_match_util_1.FAM_LexicalMatch_Util.score(set.queryTerms, {
|
|
@@ -466,7 +474,7 @@ class FAM_Retrieval_ControlService {
|
|
|
466
474
|
table: set.table,
|
|
467
475
|
score: set.vectorHit.score,
|
|
468
476
|
weight: set.weight,
|
|
469
|
-
finalScore: set.vectorHit.score * set.weight * chunkFactor * sourceFactor * summaryFactor * decayFactor * keywordBoost,
|
|
477
|
+
finalScore: set.vectorHit.score * FAM_Retrieval_ControlService.effectiveWeight(set.weight, set.config.weightInfluence) * chunkFactor * sourceFactor * summaryFactor * decayFactor * keywordBoost,
|
|
470
478
|
lexicalScore: lexicalScore,
|
|
471
479
|
content: set.includeContent ? set.entry.content : undefined,
|
|
472
480
|
contentHash: set.entry.contentHash,
|
|
@@ -485,6 +493,18 @@ class FAM_Retrieval_ControlService {
|
|
|
485
493
|
lastModifiedMs: lastModified ? new Date(lastModified).getTime() : 0,
|
|
486
494
|
};
|
|
487
495
|
}
|
|
496
|
+
/**
|
|
497
|
+
* A statikus `weight` TEMPERÁLT (effektív) értéke (PURE, 2026-08-14 lelet). A `finalScore` eddig LINEÁRISAN
|
|
498
|
+
* szorzott a weight-tel, a koszinusz viszont csak ~0.3-0.8 között mozog — így egy `weight:5` tétel
|
|
499
|
+
* MATEMATIKAILAG VERHETETLEN volt. Mérve a `rules` táron: 2 db w5-os bejegyzés ült MINDEN szabály-keresés
|
|
500
|
+
* tetején (0.519 × 5 = 2.595, míg a HELYES találat 0.621 × 1 = 0.742) — a súly ELNYOMTA a relevanciát.
|
|
501
|
+
* Mostantól `1 + influence × (weight - 1)`: a weight DÖNTETLENT BONT a kurált tartalom felé, de nem ír felül
|
|
502
|
+
* egy tisztán jobb szemantikai egyezést. Az AZONOS súlyú tételek sorrendje VÁLTOZATLAN. `influence:1` = a régi
|
|
503
|
+
* lineáris viselkedés, `0` = a weight figyelmen kívül. A `weight <= 0` (KIZÁRÁS) érintetlen marad.
|
|
504
|
+
*/
|
|
505
|
+
static effectiveWeight(weight, influence) {
|
|
506
|
+
return weight <= 0 ? weight : 1 + influence * (weight - 1);
|
|
507
|
+
}
|
|
488
508
|
/**
|
|
489
509
|
* A `rules` tár per-tár metaadatai a hit-en (`category`/`isActive`/`applicableScopes`) — FEAT-005/006 P1:
|
|
490
510
|
* a zóna-alapú aktív-rule kezelés alapja, hogy a hívó/hook a keresési hit-ből is lássa, MI aktív + mely
|
|
@@ -592,7 +612,17 @@ class FAM_Retrieval_ControlService {
|
|
|
592
612
|
// query-n `#codeExact = 0` → `effectiveTopK = topK` (változatlan viselkedés).
|
|
593
613
|
const codeExactCount = set.relevantSet.filter((hit) => this.codeExactRank(hit)).length;
|
|
594
614
|
const effectiveTopK = Math.max(set.config.topK, codeExactCount);
|
|
595
|
-
|
|
615
|
+
// Diverzitas (dogfood 2026-08-22): a top-K slotok 44%-a ugyanannak a fajlnak masik chunkja volt, es tobb-taras
|
|
616
|
+
// query-ben a `rules` 0/3 aranyban tunt el a `documents` mogott. A demote SOHA nem dob el talalatot, ezert a
|
|
617
|
+
// `confidentSet`/`totalRelevant` statisztika (lentebb, a teljes halmazon) valtozatlan marad.
|
|
618
|
+
const diversified = fam_result_diversity_util_1.FAM_ResultDiversity_Util.diversify({
|
|
619
|
+
hits: set.relevantSet,
|
|
620
|
+
maxChunksPerFile: set.config.maxChunksPerFile,
|
|
621
|
+
tableMinShare: set.query.tables.length > 1 ? set.config.tableMinShare : 0,
|
|
622
|
+
windowSize: effectiveTopK,
|
|
623
|
+
isPinned: (hit) => !!this.codeExactRank(hit),
|
|
624
|
+
});
|
|
625
|
+
const returnedHits = diversified.slice(0, effectiveTopK);
|
|
596
626
|
// Magabiztosan releváns halmaz: a nyers cosine `score` (NEM finalScore — a weight ranking-boost, nem
|
|
597
627
|
// relevancia) a `relevanceFloor` felett. A relevantSet rendezett, ezért a confidentSet is.
|
|
598
628
|
const confidentSet = set.relevantSet.filter((hit) => hit.score >= set.config.relevanceFloor);
|
|
@@ -646,7 +676,7 @@ class FAM_Retrieval_ControlService {
|
|
|
646
676
|
query: set.query,
|
|
647
677
|
effectiveTopK: set.effectiveTopK,
|
|
648
678
|
truncated: set.truncated,
|
|
649
|
-
maxPageSize: MAX_PAGE_SIZE,
|
|
679
|
+
maxPageSize: exports.MAX_PAGE_SIZE,
|
|
650
680
|
});
|
|
651
681
|
}
|
|
652
682
|
// =========================================================================
|
|
@@ -669,13 +699,16 @@ class FAM_Retrieval_ControlService {
|
|
|
669
699
|
? await this.resolveNumber(config, 'read.deepTopK', ctx, 25)
|
|
670
700
|
: await this.resolveNumber(config, 'read.topK', ctx, 5));
|
|
671
701
|
const minScore = query.minScore ?? await this.resolveNumber(config, 'read.minScore', ctx, 0);
|
|
672
|
-
const relevanceFloor = await this.resolveNumber(config, 'read.relevanceFloor', ctx, 0.
|
|
702
|
+
const relevanceFloor = await this.resolveNumber(config, 'read.relevanceFloor', ctx, 0.60);
|
|
673
703
|
const importChunkWeight = await this.resolveNumber(config, 'read.importChunkWeight', ctx, 0.4);
|
|
674
704
|
const importSourceWeight = await this.resolveNumber(config, 'read.importSourceWeight', ctx, 0.85);
|
|
675
|
-
const scanSummaryWeight = await this.resolveNumber(config, 'read.scanSummaryWeight', ctx,
|
|
705
|
+
const scanSummaryWeight = await this.resolveNumber(config, 'read.scanSummaryWeight', ctx, 0.8);
|
|
676
706
|
const keywordWeight = await this.resolveNumber(config, 'read.keywordWeight', ctx, 0.6);
|
|
707
|
+
const weightInfluence = await this.resolveNumber(config, 'read.weightInfluence', ctx, 0.06);
|
|
677
708
|
const denseResultRatio = await this.resolveNumber(config, 'read.denseResultRatio', ctx, 2.0);
|
|
678
709
|
const denseResultAbsMin = await this.resolveNumber(config, 'read.denseResultAbsMin', ctx, 25);
|
|
710
|
+
const maxChunksPerFile = await this.resolveNumber(config, 'read.maxChunksPerFile', ctx, 2);
|
|
711
|
+
const tableMinShare = await this.resolveNumber(config, 'read.tableMinShare', ctx, 1);
|
|
679
712
|
const scoreOrderValue = (await config.resolve('read.scoreOrder', ctx)).value;
|
|
680
713
|
const scoreOrder = typeof scoreOrderValue === 'string' ? scoreOrderValue : 'weighted';
|
|
681
714
|
// Memory Activation Model (dsgn-013) — a `memory.*` namespace; a decay CSAK a memory táron alkalmazódik (toHit).
|
|
@@ -692,15 +725,18 @@ class FAM_Retrieval_ControlService {
|
|
|
692
725
|
const memoryColdSearchMaxCandidates = await this.resolveNumber(config, 'memory.coldSearchMaxCandidates', ctx, 5000);
|
|
693
726
|
const memorySupersededPenalty = await this.resolveNumber(config, 'memory.supersededPenalty', ctx, 0.25);
|
|
694
727
|
return {
|
|
695
|
-
topK: Math.min(topKDefault, MAX_PAGE_SIZE),
|
|
728
|
+
topK: Math.min(topKDefault, exports.MAX_PAGE_SIZE),
|
|
696
729
|
minScore: minScore,
|
|
697
730
|
relevanceFloor: relevanceFloor,
|
|
698
731
|
importChunkWeight: importChunkWeight,
|
|
699
732
|
importSourceWeight: importSourceWeight,
|
|
700
733
|
scanSummaryWeight: scanSummaryWeight,
|
|
701
734
|
keywordWeight: keywordWeight,
|
|
735
|
+
weightInfluence: weightInfluence,
|
|
702
736
|
denseResultRatio: denseResultRatio,
|
|
703
737
|
denseResultAbsMin: denseResultAbsMin,
|
|
738
|
+
maxChunksPerFile: maxChunksPerFile,
|
|
739
|
+
tableMinShare: tableMinShare,
|
|
704
740
|
scoreOrder: scoreOrder,
|
|
705
741
|
memoryActivationEnabled: memoryActivationEnabled,
|
|
706
742
|
memoryHalfLifeDays: memoryHalfLifeDays,
|
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
* opcionális relevance-filter = BACKLOG (NEM épül).
|
|
11
11
|
*/
|
|
12
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
-
exports.FAM_RetrievalSuggestions_Util = exports.FAM_RetrievalCandidate_DataService = exports.FAM_RuleScopeContext_Util = exports.FAM_RulePropagation_Util = exports.FAM_RuleInjection_Util = exports.FAM_RuleInjection_ControlService = exports.FAM_GlobalRule_ControlService = exports.FAM_Retrieval_ControlService = void 0;
|
|
13
|
+
exports.FAM_RetrievalSuggestions_Util = exports.FAM_RetrievalCandidate_DataService = exports.FAM_RuleScopeContext_Util = exports.FAM_RulePropagation_Util = exports.FAM_RuleInjection_Util = exports.FAM_RuleInjection_ControlService = exports.FAM_GlobalRule_ControlService = exports.MAX_PAGE_SIZE = exports.FAM_Retrieval_ControlService = void 0;
|
|
14
14
|
// SP-5.1/5.2/5.3 — a read-pipeline orchestrátor
|
|
15
15
|
var fam_retrieval_control_service_1 = require("./_services/fam-retrieval.control-service");
|
|
16
16
|
Object.defineProperty(exports, "FAM_Retrieval_ControlService", { enumerable: true, get: function () { return fam_retrieval_control_service_1.FAM_Retrieval_ControlService; } });
|
|
17
|
+
Object.defineProperty(exports, "MAX_PAGE_SIZE", { enumerable: true, get: function () { return fam_retrieval_control_service_1.MAX_PAGE_SIZE; } });
|
|
17
18
|
var fam_global_rule_control_service_1 = require("./_services/fam-global-rule.control-service");
|
|
18
19
|
Object.defineProperty(exports, "FAM_GlobalRule_ControlService", { enumerable: true, get: function () { return fam_global_rule_control_service_1.FAM_GlobalRule_ControlService; } });
|
|
19
20
|
// Rules-Management MP-2 — always-apply rule-injektálás (SessionStart inject + read-reflex) szerver-oldali assembly
|
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.153",
|
|
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": {
|