@dzhechkov/memory 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +30 -0
- package/dist/backend.d.ts +45 -0
- package/dist/backend.d.ts.map +1 -0
- package/dist/backend.js +7 -0
- package/dist/backend.js.map +1 -0
- package/dist/bridge.d.ts +32 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.js +79 -0
- package/dist/bridge.js.map +1 -0
- package/dist/cascade.d.ts +32 -0
- package/dist/cascade.d.ts.map +1 -0
- package/dist/cascade.js +30 -0
- package/dist/cascade.js.map +1 -0
- package/dist/dreaming.d.ts +37 -0
- package/dist/dreaming.d.ts.map +1 -0
- package/dist/dreaming.js +102 -0
- package/dist/dreaming.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/json-backend.d.ts +33 -0
- package/dist/json-backend.d.ts.map +1 -0
- package/dist/json-backend.js +88 -0
- package/dist/json-backend.js.map +1 -0
- package/dist/reflexion.d.ts +37 -0
- package/dist/reflexion.d.ts.map +1 -0
- package/dist/reflexion.js +62 -0
- package/dist/reflexion.js.map +1 -0
- package/dist/sqlite-backend.d.ts +44 -0
- package/dist/sqlite-backend.d.ts.map +1 -0
- package/dist/sqlite-backend.js +213 -0
- package/dist/sqlite-backend.js.map +1 -0
- package/dist/sqlite-probe.d.ts +27 -0
- package/dist/sqlite-probe.d.ts.map +1 -0
- package/dist/sqlite-probe.js +34 -0
- package/dist/sqlite-probe.js.map +1 -0
- package/package.json +55 -0
- package/src/backend.ts +47 -0
- package/src/bridge.ts +99 -0
- package/src/cascade.ts +52 -0
- package/src/dreaming.ts +127 -0
- package/src/index.ts +24 -0
- package/src/json-backend.ts +109 -0
- package/src/reflexion.ts +79 -0
- package/src/sqlite-backend.ts +263 -0
- package/src/sqlite-probe.ts +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# @dzhechkov/memory
|
|
2
|
+
|
|
3
|
+
The harness **memory layer** — records skill outcomes, ranks skills, and imports
|
|
4
|
+
host memory files.
|
|
5
|
+
|
|
6
|
+
## What it provides
|
|
7
|
+
|
|
8
|
+
| Module | Exports | Purpose |
|
|
9
|
+
|---|---|---|
|
|
10
|
+
| `backend` | `MemoryBackend`, `MemoryRecord`, `MemoryQuery` | The storage contract |
|
|
11
|
+
| `json-backend` | `JsonFileBackend` | The default backend — pure JS, zero-dependency, JSON-file persistence, scored keyword retrieval |
|
|
12
|
+
| `cascade` | `selectBackend`, `BackendProbe` | Probe optional backends, fall back gracefully |
|
|
13
|
+
| `reflexion` | `Reflexion` | Record skill outcomes (`record(skillId, outcome, score)`); rank skills |
|
|
14
|
+
| `bridge` | `MemoryBridge`, `importMemoryMarkdown` | Import a host memory markdown file into `MemoryRecord`s |
|
|
15
|
+
|
|
16
|
+
## Backend strategy
|
|
17
|
+
|
|
18
|
+
The default `JsonFileBackend` is **pure JavaScript with zero dependencies** — no
|
|
19
|
+
native build, no WASM, no model download — so it works everywhere and is fully
|
|
20
|
+
testable.
|
|
21
|
+
|
|
22
|
+
`selectBackend` is the **cascade**: it probes a list of optional backends (a
|
|
23
|
+
vector/embedding backend can be registered here later) and falls back to a
|
|
24
|
+
guaranteed backend if none is available. Heavier backends (`agentdb`, `sql.js`)
|
|
25
|
+
are intentionally *not* hard dependencies — see
|
|
26
|
+
`features/extended-a-migration/autonomous-log/decisions.md` (D7.1).
|
|
27
|
+
|
|
28
|
+
## Status
|
|
29
|
+
|
|
30
|
+
`0.1.0` — alpha, part of the `extended-a-migration` feature (Phase 7).
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The memory storage contract — what every backend implements.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
/** A single memory entry. */
|
|
7
|
+
export interface MemoryRecord {
|
|
8
|
+
/** Unique record id. */
|
|
9
|
+
readonly id: string;
|
|
10
|
+
/** The skill this record is about. */
|
|
11
|
+
readonly skillId: string;
|
|
12
|
+
/** Free text — the content keyword queries match against. */
|
|
13
|
+
readonly text: string;
|
|
14
|
+
/** Reward / quality score, in `[0, 1]`. */
|
|
15
|
+
readonly score: number;
|
|
16
|
+
/** A short outcome label, e.g. `excellent`, `good`, `imported`. */
|
|
17
|
+
readonly outcome: string;
|
|
18
|
+
/** ISO-8601 creation time. */
|
|
19
|
+
readonly timestamp: string;
|
|
20
|
+
/** Optional string-keyed metadata. */
|
|
21
|
+
readonly metadata?: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
/** A retrieval query. */
|
|
24
|
+
export interface MemoryQuery {
|
|
25
|
+
/** Keyword text to rank records by relevance. */
|
|
26
|
+
readonly text?: string;
|
|
27
|
+
/** Restrict to one skill. */
|
|
28
|
+
readonly skillId?: string;
|
|
29
|
+
/** Maximum results (default 20). */
|
|
30
|
+
readonly limit?: number;
|
|
31
|
+
}
|
|
32
|
+
/** A pluggable memory store. */
|
|
33
|
+
export interface MemoryBackend {
|
|
34
|
+
/** Stable backend name, e.g. `json-file`. */
|
|
35
|
+
readonly name: string;
|
|
36
|
+
/** Insert or replace a record (keyed by `record.id`). */
|
|
37
|
+
put(record: MemoryRecord): Promise<void>;
|
|
38
|
+
/** Retrieve records ranked by relevance to the query. */
|
|
39
|
+
query(query: MemoryQuery): Promise<MemoryRecord[]>;
|
|
40
|
+
/** Every stored record. */
|
|
41
|
+
all(): Promise<MemoryRecord[]>;
|
|
42
|
+
/** Number of stored records. */
|
|
43
|
+
count(): Promise<number>;
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,6BAA6B;AAC7B,MAAM,WAAW,YAAY;IAC3B,wBAAwB;IACxB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2CAA2C;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,8BAA8B;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,sCAAsC;IACtC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5C;AAED,yBAAyB;AACzB,MAAM,WAAW,WAAW;IAC1B,iDAAiD;IACjD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,6BAA6B;IAC7B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,oCAAoC;IACpC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,gCAAgC;AAChC,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,yDAAyD;IACzD,GAAG,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,yDAAyD;IACzD,KAAK,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IACnD,2BAA2B;IAC3B,GAAG,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IAC/B,gCAAgC;IAChC,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CAC1B"}
|
package/dist/backend.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
package/dist/bridge.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `MemoryBridge` — import host memory files into canonical `MemoryRecord`s.
|
|
3
|
+
*
|
|
4
|
+
* The bridge is the anti-corruption layer between a host's memory format
|
|
5
|
+
* (a Claude Code `MEMORY.md`, a memory note, …) and this package's records.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
import type { MemoryBackend, MemoryRecord } from './backend.js';
|
|
10
|
+
/** Options for a bridge import. */
|
|
11
|
+
export interface BridgeOptions {
|
|
12
|
+
/** A label for where the memory came from, e.g. `claude-code:MEMORY.md`. */
|
|
13
|
+
readonly source: string;
|
|
14
|
+
/** Skill id to associate the imported records with. Default `imported`. */
|
|
15
|
+
readonly skillId?: string;
|
|
16
|
+
/** Score for imported records, in `[0, 1]`. Default `0.5`. */
|
|
17
|
+
readonly score?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parse a host memory markdown document into {@link MemoryRecord}s — one record
|
|
21
|
+
* per `##` section (or one for the whole document if it has no headings).
|
|
22
|
+
* Empty sections are dropped. Pure: it does not touch any backend.
|
|
23
|
+
*/
|
|
24
|
+
export declare function importMemoryMarkdown(markdown: string, options: BridgeOptions): MemoryRecord[];
|
|
25
|
+
/** Imports host memory markdown into a {@link MemoryBackend}. */
|
|
26
|
+
export declare class MemoryBridge {
|
|
27
|
+
private readonly backend;
|
|
28
|
+
constructor(backend: MemoryBackend);
|
|
29
|
+
/** Parse `markdown` and store each resulting record; returns the records. */
|
|
30
|
+
importMarkdown(markdown: string, options: BridgeOptions): Promise<MemoryRecord[]>;
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAKhE,mCAAmC;AACnC,MAAM,WAAW,aAAa;IAC5B,4EAA4E;IAC5E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAuCD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,YAAY,EAAE,CAkB7F;AAED,iEAAiE;AACjE,qBAAa,YAAY;IACX,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,aAAa;IAEnD,6EAA6E;IACvE,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;CAOxF"}
|
package/dist/bridge.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `MemoryBridge` — import host memory files into canonical `MemoryRecord`s.
|
|
3
|
+
*
|
|
4
|
+
* The bridge is the anti-corruption layer between a host's memory format
|
|
5
|
+
* (a Claude Code `MEMORY.md`, a memory note, …) and this package's records.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
/** Monotonic counter for bridge-generated record ids. */
|
|
10
|
+
let sequence = 0;
|
|
11
|
+
function slug(text) {
|
|
12
|
+
return (text
|
|
13
|
+
.toLowerCase()
|
|
14
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
15
|
+
.replace(/^-+|-+$/g, '')
|
|
16
|
+
.slice(0, 48) || 'section');
|
|
17
|
+
}
|
|
18
|
+
/** Split markdown into sections on `##` headings (whole doc if there are none). */
|
|
19
|
+
function splitSections(markdown) {
|
|
20
|
+
const sections = [];
|
|
21
|
+
let heading = 'document';
|
|
22
|
+
let body = [];
|
|
23
|
+
const flush = () => {
|
|
24
|
+
sections.push({ heading, body: body.join('\n') });
|
|
25
|
+
};
|
|
26
|
+
for (const line of markdown.split(/\r?\n/)) {
|
|
27
|
+
const match = /^##\s+(.+?)\s*$/.exec(line);
|
|
28
|
+
if (match) {
|
|
29
|
+
flush();
|
|
30
|
+
heading = match[1] ?? 'section';
|
|
31
|
+
body = [];
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
body.push(line);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
flush();
|
|
38
|
+
return sections;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Parse a host memory markdown document into {@link MemoryRecord}s — one record
|
|
42
|
+
* per `##` section (or one for the whole document if it has no headings).
|
|
43
|
+
* Empty sections are dropped. Pure: it does not touch any backend.
|
|
44
|
+
*/
|
|
45
|
+
export function importMemoryMarkdown(markdown, options) {
|
|
46
|
+
const skillId = options.skillId ?? 'imported';
|
|
47
|
+
const score = options.score ?? 0.5;
|
|
48
|
+
const timestamp = new Date().toISOString();
|
|
49
|
+
return splitSections(markdown)
|
|
50
|
+
.map((section) => {
|
|
51
|
+
sequence += 1;
|
|
52
|
+
return {
|
|
53
|
+
id: `bridge:${slug(options.source)}:${slug(section.heading)}:${sequence}`,
|
|
54
|
+
skillId,
|
|
55
|
+
text: section.body.trim(),
|
|
56
|
+
score,
|
|
57
|
+
outcome: 'imported',
|
|
58
|
+
timestamp,
|
|
59
|
+
metadata: { source: options.source, heading: section.heading },
|
|
60
|
+
};
|
|
61
|
+
})
|
|
62
|
+
.filter((record) => record.text.length > 0);
|
|
63
|
+
}
|
|
64
|
+
/** Imports host memory markdown into a {@link MemoryBackend}. */
|
|
65
|
+
export class MemoryBridge {
|
|
66
|
+
backend;
|
|
67
|
+
constructor(backend) {
|
|
68
|
+
this.backend = backend;
|
|
69
|
+
}
|
|
70
|
+
/** Parse `markdown` and store each resulting record; returns the records. */
|
|
71
|
+
async importMarkdown(markdown, options) {
|
|
72
|
+
const records = importMemoryMarkdown(markdown, options);
|
|
73
|
+
for (const record of records) {
|
|
74
|
+
await this.backend.put(record);
|
|
75
|
+
}
|
|
76
|
+
return records;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.js","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,yDAAyD;AACzD,IAAI,QAAQ,GAAG,CAAC,CAAC;AAiBjB,SAAS,IAAI,CAAC,IAAY;IACxB,OAAO,CACL,IAAI;SACD,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,SAAS,CAC7B,CAAC;AACJ,CAAC;AAED,mFAAmF;AACnF,SAAS,aAAa,CAAC,QAAgB;IACrC,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,IAAI,OAAO,GAAG,UAAU,CAAC;IACzB,IAAI,IAAI,GAAa,EAAE,CAAC;IACxB,MAAM,KAAK,GAAG,GAAS,EAAE;QACvB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACpD,CAAC,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3C,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,EAAE,CAAC;YACR,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;YAChC,IAAI,GAAG,EAAE,CAAC;QACZ,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IACD,KAAK,EAAE,CAAC;IACR,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAgB,EAAE,OAAsB;IAC3E,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,UAAU,CAAC;IAC9C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,GAAG,CAAC;IACnC,MAAM,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC3C,OAAO,aAAa,CAAC,QAAQ,CAAC;SAC3B,GAAG,CAAC,CAAC,OAAO,EAAgB,EAAE;QAC7B,QAAQ,IAAI,CAAC,CAAC;QACd,OAAO;YACL,EAAE,EAAE,UAAU,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,QAAQ,EAAE;YACzE,OAAO;YACP,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE;YACzB,KAAK;YACL,OAAO,EAAE,UAAU;YACnB,SAAS;YACT,QAAQ,EAAE,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE;SAC/D,CAAC;IACJ,CAAC,CAAC;SACD,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AAChD,CAAC;AAED,iEAAiE;AACjE,MAAM,OAAO,YAAY;IACM;IAA7B,YAA6B,OAAsB;QAAtB,YAAO,GAAP,OAAO,CAAe;IAAG,CAAC;IAEvD,6EAA6E;IAC7E,KAAK,CAAC,cAAc,CAAC,QAAgB,EAAE,OAAsB;QAC3D,MAAM,OAAO,GAAG,oBAAoB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACxD,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;CACF"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The backend cascade — probe optional backends, fall back gracefully.
|
|
3
|
+
*
|
|
4
|
+
* Heavier backends (a vector / embedding store, `agentdb`, `sql.js`) can be
|
|
5
|
+
* registered as probes. If none initialises, a guaranteed fallback is used.
|
|
6
|
+
* This keeps such backends *optional* — never a hard dependency.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import type { MemoryBackend } from './backend.js';
|
|
11
|
+
/** A candidate backend the cascade may select. */
|
|
12
|
+
export interface BackendProbe {
|
|
13
|
+
/** Probe name, for the `tried` log. */
|
|
14
|
+
readonly name: string;
|
|
15
|
+
/** Try to create the backend; resolve `undefined` (or throw) if unavailable. */
|
|
16
|
+
create(): Promise<MemoryBackend | undefined>;
|
|
17
|
+
}
|
|
18
|
+
/** The outcome of {@link selectBackend}. */
|
|
19
|
+
export interface CascadeResult {
|
|
20
|
+
/** The selected backend. */
|
|
21
|
+
readonly backend: MemoryBackend;
|
|
22
|
+
/** Name of the selected backend (probe name, or the fallback's name). */
|
|
23
|
+
readonly selected: string;
|
|
24
|
+
/** Probe names attempted, in order. */
|
|
25
|
+
readonly tried: string[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Walk `probes` in order; return the first backend that initialises. If every
|
|
29
|
+
* probe is unavailable (returns `undefined` or throws), return `fallback`.
|
|
30
|
+
*/
|
|
31
|
+
export declare function selectBackend(probes: readonly BackendProbe[], fallback: MemoryBackend): Promise<CascadeResult>;
|
|
32
|
+
//# sourceMappingURL=cascade.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cascade.d.ts","sourceRoot":"","sources":["../src/cascade.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,kDAAkD;AAClD,MAAM,WAAW,YAAY;IAC3B,uCAAuC;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gFAAgF;IAChF,MAAM,IAAI,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAAC;CAC9C;AAED,4CAA4C;AAC5C,MAAM,WAAW,aAAa;IAC5B,4BAA4B;IAC5B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;IAChC,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uCAAuC;IACvC,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,QAAQ,EAAE,aAAa,GACtB,OAAO,CAAC,aAAa,CAAC,CAcxB"}
|
package/dist/cascade.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The backend cascade — probe optional backends, fall back gracefully.
|
|
3
|
+
*
|
|
4
|
+
* Heavier backends (a vector / embedding store, `agentdb`, `sql.js`) can be
|
|
5
|
+
* registered as probes. If none initialises, a guaranteed fallback is used.
|
|
6
|
+
* This keeps such backends *optional* — never a hard dependency.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Walk `probes` in order; return the first backend that initialises. If every
|
|
12
|
+
* probe is unavailable (returns `undefined` or throws), return `fallback`.
|
|
13
|
+
*/
|
|
14
|
+
export async function selectBackend(probes, fallback) {
|
|
15
|
+
const tried = [];
|
|
16
|
+
for (const probe of probes) {
|
|
17
|
+
tried.push(probe.name);
|
|
18
|
+
try {
|
|
19
|
+
const backend = await probe.create();
|
|
20
|
+
if (backend !== undefined) {
|
|
21
|
+
return { backend, selected: probe.name, tried };
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
// probe unavailable — fall through to the next
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return { backend: fallback, selected: fallback.name, tried };
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=cascade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cascade.js","sourceRoot":"","sources":["../src/cascade.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAsBH;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAA+B,EAC/B,QAAuB;IAEvB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACvB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,MAAM,EAAE,CAAC;YACrC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;gBAC1B,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;YAClD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,+CAA+C;QACjD,CAAC;IACH,CAAC;IACD,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent SDK Dreaming integration — bridges Opus 4.8 Dreaming with Reflexion.
|
|
3
|
+
*
|
|
4
|
+
* Per ADR-005: this is orchestration-layer code. It reads session JSONL files
|
|
5
|
+
* (produced by Agent SDK), extracts patterns, and feeds them into the Reflexion
|
|
6
|
+
* system. The MemoryBackend interface is unchanged.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import type { MemoryRecord } from './backend.js';
|
|
11
|
+
/** A pattern extracted from an Agent SDK session. */
|
|
12
|
+
export interface DreamPattern {
|
|
13
|
+
readonly skillId: string;
|
|
14
|
+
readonly outcome: 'excellent' | 'good' | 'needs_work' | 'failed';
|
|
15
|
+
readonly score: number;
|
|
16
|
+
readonly insight: string;
|
|
17
|
+
readonly sessionFile: string;
|
|
18
|
+
readonly timestamp: string;
|
|
19
|
+
}
|
|
20
|
+
/** Options for the dream harvester. */
|
|
21
|
+
export interface DreamOptions {
|
|
22
|
+
/** Directory containing Agent SDK session JSONL files. */
|
|
23
|
+
readonly sessionsDir: string;
|
|
24
|
+
/** Only process sessions newer than this ISO timestamp. */
|
|
25
|
+
readonly since?: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Harvest patterns from Agent SDK session files.
|
|
29
|
+
*
|
|
30
|
+
* Scans `.jsonl` files in `sessionsDir`, extracts tool-use outcomes
|
|
31
|
+
* and skill invocations, and returns them as `DreamPattern`s ready
|
|
32
|
+
* to be fed into Reflexion via `reflexion.record()`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function harvestDreamPatterns(options: DreamOptions): DreamPattern[];
|
|
35
|
+
/** Convert a DreamPattern to a MemoryRecord for storage via any MemoryBackend. */
|
|
36
|
+
export declare function dreamPatternToRecord(pattern: DreamPattern): MemoryRecord;
|
|
37
|
+
//# sourceMappingURL=dreaming.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dreaming.d.ts","sourceRoot":"","sources":["../src/dreaming.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,qDAAqD;AACrD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM,GAAG,YAAY,GAAG,QAAQ,CAAC;IACjE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,uCAAuC;AACvC,MAAM,WAAW,YAAY;IAC3B,0DAA0D;IAC1D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,YAAY,EAAE,CAyE1E;AAED,kFAAkF;AAClF,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,YAAY,CAUxE"}
|
package/dist/dreaming.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent SDK Dreaming integration — bridges Opus 4.8 Dreaming with Reflexion.
|
|
3
|
+
*
|
|
4
|
+
* Per ADR-005: this is orchestration-layer code. It reads session JSONL files
|
|
5
|
+
* (produced by Agent SDK), extracts patterns, and feeds them into the Reflexion
|
|
6
|
+
* system. The MemoryBackend interface is unchanged.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
/**
|
|
13
|
+
* Harvest patterns from Agent SDK session files.
|
|
14
|
+
*
|
|
15
|
+
* Scans `.jsonl` files in `sessionsDir`, extracts tool-use outcomes
|
|
16
|
+
* and skill invocations, and returns them as `DreamPattern`s ready
|
|
17
|
+
* to be fed into Reflexion via `reflexion.record()`.
|
|
18
|
+
*/
|
|
19
|
+
export function harvestDreamPatterns(options) {
|
|
20
|
+
const { sessionsDir, since } = options;
|
|
21
|
+
if (!existsSync(sessionsDir))
|
|
22
|
+
return [];
|
|
23
|
+
const patterns = [];
|
|
24
|
+
const files = readdirSync(sessionsDir)
|
|
25
|
+
.filter((f) => f.endsWith('.jsonl'))
|
|
26
|
+
.sort();
|
|
27
|
+
for (const file of files) {
|
|
28
|
+
const filePath = join(sessionsDir, file);
|
|
29
|
+
const lines = readFileSync(filePath, 'utf-8').split('\n').filter((l) => l.trim().length > 0);
|
|
30
|
+
for (const line of lines) {
|
|
31
|
+
try {
|
|
32
|
+
const entry = JSON.parse(line);
|
|
33
|
+
// Skip entries older than `since`
|
|
34
|
+
if (since !== undefined && entry.timestamp && entry.timestamp < since)
|
|
35
|
+
continue;
|
|
36
|
+
// Extract skill invocations from tool_use messages
|
|
37
|
+
if (entry.type === 'assistant' && entry.message?.content) {
|
|
38
|
+
const content = Array.isArray(entry.message.content) ? entry.message.content : [entry.message.content];
|
|
39
|
+
for (const block of content) {
|
|
40
|
+
if (block.type === 'tool_use' && block.name?.startsWith?.('mcp__')) {
|
|
41
|
+
// MCP tool invocation — extract skill context
|
|
42
|
+
const skillId = block.input?.targetPath ?? block.input?.scope ?? 'unknown';
|
|
43
|
+
patterns.push({
|
|
44
|
+
skillId: typeof skillId === 'string' ? skillId : 'unknown',
|
|
45
|
+
outcome: 'good',
|
|
46
|
+
score: 0.7,
|
|
47
|
+
insight: `Tool ${block.name} invoked during session`,
|
|
48
|
+
sessionFile: file,
|
|
49
|
+
timestamp: entry.timestamp ?? new Date().toISOString(),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// Extract checkpoint responses (reward signals)
|
|
55
|
+
if (entry.type === 'user' && typeof entry.message?.content === 'string') {
|
|
56
|
+
const text = entry.message.content.toLowerCase();
|
|
57
|
+
let outcome = 'good';
|
|
58
|
+
let score = 0.7;
|
|
59
|
+
if (text === 'ок' || text === 'ok' || text === 'next' || text === 'продолжай') {
|
|
60
|
+
outcome = 'excellent';
|
|
61
|
+
score = 1.0;
|
|
62
|
+
}
|
|
63
|
+
else if (text.includes('переделай') || text.includes('rework') || text.includes('заново')) {
|
|
64
|
+
outcome = 'needs_work';
|
|
65
|
+
score = 0.3;
|
|
66
|
+
}
|
|
67
|
+
else if (text.includes('стоп') || text.includes('stop') || text.includes('wrong')) {
|
|
68
|
+
outcome = 'failed';
|
|
69
|
+
score = 0.0;
|
|
70
|
+
}
|
|
71
|
+
if (outcome !== 'good') {
|
|
72
|
+
patterns.push({
|
|
73
|
+
skillId: 'checkpoint-response',
|
|
74
|
+
outcome,
|
|
75
|
+
score,
|
|
76
|
+
insight: `User responded: "${entry.message.content.slice(0, 100)}"`,
|
|
77
|
+
sessionFile: file,
|
|
78
|
+
timestamp: entry.timestamp ?? new Date().toISOString(),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// Skip malformed JSONL lines
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return patterns;
|
|
89
|
+
}
|
|
90
|
+
/** Convert a DreamPattern to a MemoryRecord for storage via any MemoryBackend. */
|
|
91
|
+
export function dreamPatternToRecord(pattern) {
|
|
92
|
+
return {
|
|
93
|
+
id: `dream:${pattern.sessionFile}:${pattern.skillId}:${Date.now()}`,
|
|
94
|
+
skillId: pattern.skillId,
|
|
95
|
+
text: pattern.insight,
|
|
96
|
+
score: pattern.score,
|
|
97
|
+
outcome: pattern.outcome,
|
|
98
|
+
timestamp: pattern.timestamp,
|
|
99
|
+
metadata: { sessionFile: pattern.sessionFile },
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=dreaming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dreaming.js","sourceRoot":"","sources":["../src/dreaming.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@dzhechkov/memory` — the harness memory layer.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
/** Package version. Kept in sync with `package.json`. */
|
|
7
|
+
export declare const MEMORY_VERSION = "0.1.0";
|
|
8
|
+
export type { MemoryBackend, MemoryQuery, MemoryRecord } from './backend.js';
|
|
9
|
+
export { JsonFileBackend } from './json-backend.js';
|
|
10
|
+
export type { JsonFileBackendOptions } from './json-backend.js';
|
|
11
|
+
export { selectBackend } from './cascade.js';
|
|
12
|
+
export type { BackendProbe, CascadeResult } from './cascade.js';
|
|
13
|
+
export { SqliteBackend } from './sqlite-backend.js';
|
|
14
|
+
export type { SqliteBackendOptions } from './sqlite-backend.js';
|
|
15
|
+
export { SqliteProbe } from './sqlite-probe.js';
|
|
16
|
+
export type { SqliteProbeOptions } from './sqlite-probe.js';
|
|
17
|
+
export { Reflexion } from './reflexion.js';
|
|
18
|
+
export type { ReflexionInput } from './reflexion.js';
|
|
19
|
+
export { importMemoryMarkdown, MemoryBridge } from './bridge.js';
|
|
20
|
+
export type { BridgeOptions } from './bridge.js';
|
|
21
|
+
export { harvestDreamPatterns, dreamPatternToRecord } from './dreaming.js';
|
|
22
|
+
export type { DreamPattern, DreamOptions } from './dreaming.js';
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,yDAAyD;AACzD,eAAO,MAAM,cAAc,UAAU,CAAC;AAEtC,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACjE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC3E,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@dzhechkov/memory` — the harness memory layer.
|
|
3
|
+
*
|
|
4
|
+
* @packageDocumentation
|
|
5
|
+
*/
|
|
6
|
+
/** Package version. Kept in sync with `package.json`. */
|
|
7
|
+
export const MEMORY_VERSION = '0.1.0';
|
|
8
|
+
export { JsonFileBackend } from './json-backend.js';
|
|
9
|
+
export { selectBackend } from './cascade.js';
|
|
10
|
+
export { SqliteBackend } from './sqlite-backend.js';
|
|
11
|
+
export { SqliteProbe } from './sqlite-probe.js';
|
|
12
|
+
export { Reflexion } from './reflexion.js';
|
|
13
|
+
export { importMemoryMarkdown, MemoryBridge } from './bridge.js';
|
|
14
|
+
export { harvestDreamPatterns, dreamPatternToRecord } from './dreaming.js';
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,yDAAyD;AACzD,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAGtC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEjE,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `JsonFileBackend` — the default memory backend.
|
|
3
|
+
*
|
|
4
|
+
* Pure JavaScript, zero runtime dependencies: records live in an in-memory map
|
|
5
|
+
* and persist to a JSON file. Retrieval is scored keyword overlap. No native
|
|
6
|
+
* build, no WASM, no model download — it works everywhere.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import type { MemoryBackend, MemoryQuery, MemoryRecord } from './backend.js';
|
|
11
|
+
/** Options for {@link JsonFileBackend}. */
|
|
12
|
+
export interface JsonFileBackendOptions {
|
|
13
|
+
/** File the records persist to. Omit for an in-memory-only backend. */
|
|
14
|
+
readonly filePath?: string;
|
|
15
|
+
}
|
|
16
|
+
/** The default memory backend — in-memory map with optional JSON-file persistence. */
|
|
17
|
+
export declare class JsonFileBackend implements MemoryBackend {
|
|
18
|
+
readonly name = "json-file";
|
|
19
|
+
private readonly records;
|
|
20
|
+
private readonly filePath;
|
|
21
|
+
constructor(options?: JsonFileBackendOptions);
|
|
22
|
+
/** Create a backend and load any records already persisted at `filePath`. */
|
|
23
|
+
static open(filePath: string): Promise<JsonFileBackend>;
|
|
24
|
+
put(record: MemoryRecord): Promise<void>;
|
|
25
|
+
query(query: MemoryQuery): Promise<MemoryRecord[]>;
|
|
26
|
+
all(): Promise<MemoryRecord[]>;
|
|
27
|
+
count(): Promise<number>;
|
|
28
|
+
/** Persist every record to `filePath`. No-op when no path is configured. */
|
|
29
|
+
save(): Promise<void>;
|
|
30
|
+
/** Load records from `filePath`. No-op when no path is set or the file is absent. */
|
|
31
|
+
load(): Promise<void>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=json-backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-backend.d.ts","sourceRoot":"","sources":["../src/json-backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAuB7E,2CAA2C;AAC3C,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,sFAAsF;AACtF,qBAAa,eAAgB,YAAW,aAAa;IACnD,QAAQ,CAAC,IAAI,eAAe;IAE5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;IAC3D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAqB;gBAElC,OAAO,GAAE,sBAA2B;IAIhD,6EAA6E;WAChE,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAM7D,GAAG,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAKxC,KAAK,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAkBlD,GAAG,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAI9B,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAIxB,4EAA4E;IAC5E,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQrB,qFAAqF;IACrF,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;CAOtB"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `JsonFileBackend` — the default memory backend.
|
|
3
|
+
*
|
|
4
|
+
* Pure JavaScript, zero runtime dependencies: records live in an in-memory map
|
|
5
|
+
* and persist to a JSON file. Retrieval is scored keyword overlap. No native
|
|
6
|
+
* build, no WASM, no model download — it works everywhere.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
11
|
+
import { dirname } from 'node:path';
|
|
12
|
+
const DEFAULT_LIMIT = 20;
|
|
13
|
+
/** Split text into lowercase word tokens of length > 1. */
|
|
14
|
+
function tokenize(text) {
|
|
15
|
+
return text
|
|
16
|
+
.toLowerCase()
|
|
17
|
+
.split(/[^a-z0-9]+/)
|
|
18
|
+
.filter((token) => token.length > 1);
|
|
19
|
+
}
|
|
20
|
+
/** Count how many query terms appear in a record's text/skillId. */
|
|
21
|
+
function relevanceOf(record, terms) {
|
|
22
|
+
if (terms.length === 0)
|
|
23
|
+
return 0;
|
|
24
|
+
const haystack = new Set(tokenize(`${record.text} ${record.skillId}`));
|
|
25
|
+
let hits = 0;
|
|
26
|
+
for (const term of terms) {
|
|
27
|
+
if (haystack.has(term))
|
|
28
|
+
hits += 1;
|
|
29
|
+
}
|
|
30
|
+
return hits;
|
|
31
|
+
}
|
|
32
|
+
/** The default memory backend — in-memory map with optional JSON-file persistence. */
|
|
33
|
+
export class JsonFileBackend {
|
|
34
|
+
name = 'json-file';
|
|
35
|
+
records = new Map();
|
|
36
|
+
filePath;
|
|
37
|
+
constructor(options = {}) {
|
|
38
|
+
this.filePath = options.filePath;
|
|
39
|
+
}
|
|
40
|
+
/** Create a backend and load any records already persisted at `filePath`. */
|
|
41
|
+
static async open(filePath) {
|
|
42
|
+
const backend = new JsonFileBackend({ filePath });
|
|
43
|
+
await backend.load();
|
|
44
|
+
return backend;
|
|
45
|
+
}
|
|
46
|
+
put(record) {
|
|
47
|
+
this.records.set(record.id, record);
|
|
48
|
+
return Promise.resolve();
|
|
49
|
+
}
|
|
50
|
+
query(query) {
|
|
51
|
+
const limit = query.limit ?? DEFAULT_LIMIT;
|
|
52
|
+
const terms = query.text !== undefined ? tokenize(query.text) : [];
|
|
53
|
+
let candidates = [...this.records.values()];
|
|
54
|
+
if (query.skillId !== undefined) {
|
|
55
|
+
candidates = candidates.filter((record) => record.skillId === query.skillId);
|
|
56
|
+
}
|
|
57
|
+
const ranked = candidates
|
|
58
|
+
.map((record) => ({ record, relevance: relevanceOf(record, terms) }))
|
|
59
|
+
.sort((a, b) => b.relevance - a.relevance ||
|
|
60
|
+
b.record.score - a.record.score ||
|
|
61
|
+
b.record.timestamp.localeCompare(a.record.timestamp));
|
|
62
|
+
return Promise.resolve(ranked.slice(0, limit).map((entry) => entry.record));
|
|
63
|
+
}
|
|
64
|
+
all() {
|
|
65
|
+
return Promise.resolve([...this.records.values()]);
|
|
66
|
+
}
|
|
67
|
+
count() {
|
|
68
|
+
return Promise.resolve(this.records.size);
|
|
69
|
+
}
|
|
70
|
+
/** Persist every record to `filePath`. No-op when no path is configured. */
|
|
71
|
+
save() {
|
|
72
|
+
if (this.filePath !== undefined) {
|
|
73
|
+
mkdirSync(dirname(this.filePath), { recursive: true });
|
|
74
|
+
writeFileSync(this.filePath, JSON.stringify([...this.records.values()], null, 2));
|
|
75
|
+
}
|
|
76
|
+
return Promise.resolve();
|
|
77
|
+
}
|
|
78
|
+
/** Load records from `filePath`. No-op when no path is set or the file is absent. */
|
|
79
|
+
load() {
|
|
80
|
+
if (this.filePath !== undefined && existsSync(this.filePath)) {
|
|
81
|
+
const data = JSON.parse(readFileSync(this.filePath, 'utf-8'));
|
|
82
|
+
for (const record of data)
|
|
83
|
+
this.records.set(record.id, record);
|
|
84
|
+
}
|
|
85
|
+
return Promise.resolve();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=json-backend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-backend.js","sourceRoot":"","sources":["../src/json-backend.ts"],"names":[],"mappings":"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"}
|