@oharness/engine 0.5.0 → 0.6.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/dist/agent/agent.d.ts +63 -0
- package/dist/agent/agent.js +257 -7
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/memory-backup.d.ts +38 -0
- package/dist/agent/memory-backup.js +126 -0
- package/dist/agent/memory-backup.js.map +1 -0
- package/dist/agent/memory-consolidate.d.ts +47 -0
- package/dist/agent/memory-consolidate.js +118 -0
- package/dist/agent/memory-consolidate.js.map +1 -0
- package/dist/agent/memory-errors.d.ts +73 -0
- package/dist/agent/memory-errors.js +74 -0
- package/dist/agent/memory-errors.js.map +1 -0
- package/dist/agent/memory-extract.d.ts +36 -0
- package/dist/agent/memory-extract.js +169 -0
- package/dist/agent/memory-extract.js.map +1 -0
- package/dist/agent/memory-limits.d.ts +115 -0
- package/dist/agent/memory-limits.js +109 -0
- package/dist/agent/memory-limits.js.map +1 -0
- package/dist/agent/memory-links.d.ts +21 -0
- package/dist/agent/memory-links.js +45 -0
- package/dist/agent/memory-links.js.map +1 -0
- package/dist/agent/memory-merge.d.ts +34 -0
- package/dist/agent/memory-merge.js +152 -0
- package/dist/agent/memory-merge.js.map +1 -0
- package/dist/agent/memory-provider.d.ts +73 -0
- package/dist/agent/memory-provider.js +2 -0
- package/dist/agent/memory-provider.js.map +1 -0
- package/dist/agent/memory-recall.d.ts +72 -0
- package/dist/agent/memory-recall.js +192 -0
- package/dist/agent/memory-recall.js.map +1 -0
- package/dist/agent/memory-redact.d.ts +15 -0
- package/dist/agent/memory-redact.js +48 -0
- package/dist/agent/memory-redact.js.map +1 -0
- package/dist/agent/memory-review.d.ts +47 -0
- package/dist/agent/memory-review.js +127 -0
- package/dist/agent/memory-review.js.map +1 -0
- package/dist/agent/memory-usage.d.ts +24 -0
- package/dist/agent/memory-usage.js +68 -0
- package/dist/agent/memory-usage.js.map +1 -0
- package/dist/agent/memory.d.ts +137 -14
- package/dist/agent/memory.js +431 -130
- package/dist/agent/memory.js.map +1 -1
- package/dist/agent/permissions.d.ts +10 -2
- package/dist/agent/permissions.js +22 -3
- package/dist/agent/permissions.js.map +1 -1
- package/dist/agent/session.d.ts +8 -1
- package/dist/agent/session.js +9 -0
- package/dist/agent/session.js.map +1 -1
- package/dist/agent/store.d.ts +3 -0
- package/dist/agent/store.js.map +1 -1
- package/dist/agent/titles.js +2 -2
- package/dist/config.d.ts +7 -1
- package/dist/config.js +27 -0
- package/dist/config.js.map +1 -1
- package/dist/core/audit.d.ts +19 -0
- package/dist/core/types.d.ts +6 -0
- package/dist/core/types.js +12 -0
- package/dist/core/types.js.map +1 -1
- package/dist/harness.d.ts +7 -1
- package/dist/harness.js +33 -2
- package/dist/harness.js.map +1 -1
- package/dist/providers/builtin.d.ts +20 -0
- package/dist/providers/builtin.js +82 -0
- package/dist/providers/builtin.js.map +1 -1
- package/dist/providers/catalog.js +30 -3
- package/dist/providers/catalog.js.map +1 -1
- package/dist/providers/index.d.ts +2 -2
- package/dist/providers/index.js +1 -1
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/piai.js +17 -8
- package/dist/providers/piai.js.map +1 -1
- package/dist/providers/registry.d.ts +5 -0
- package/dist/providers/registry.js +10 -2
- package/dist/providers/registry.js.map +1 -1
- package/dist/providers/types.d.ts +31 -0
- package/dist/providers/types.js +36 -0
- package/dist/providers/types.js.map +1 -1
- package/dist/runtime-plugins/builtin/memory-coordinator.d.ts +79 -0
- package/dist/runtime-plugins/builtin/memory-coordinator.js +169 -0
- package/dist/runtime-plugins/builtin/memory-coordinator.js.map +1 -0
- package/dist/runtime-plugins/builtin/memory-migrate.d.ts +35 -0
- package/dist/runtime-plugins/builtin/memory-migrate.js +141 -0
- package/dist/runtime-plugins/builtin/memory-migrate.js.map +1 -0
- package/dist/runtime-plugins/builtin/memory.d.ts +144 -5
- package/dist/runtime-plugins/builtin/memory.js +1016 -112
- package/dist/runtime-plugins/builtin/memory.js.map +1 -1
- package/dist/runtime-plugins/builtin/studio.js +19 -4
- package/dist/runtime-plugins/builtin/studio.js.map +1 -1
- package/dist/runtime-plugins/cloud-connector.js +4 -1
- package/dist/runtime-plugins/cloud-connector.js.map +1 -1
- package/dist/runtime-plugins/extensions.d.ts +9 -0
- package/dist/runtime-plugins/extensions.js +15 -0
- package/dist/runtime-plugins/extensions.js.map +1 -1
- package/dist/runtime-plugins/host.js +24 -2
- package/dist/runtime-plugins/host.js.map +1 -1
- package/dist/runtime-plugins/types.d.ts +6 -0
- package/dist/tools/builtin/ask.d.ts +9 -0
- package/dist/tools/builtin/ask.js +71 -0
- package/dist/tools/builtin/ask.js.map +1 -0
- package/dist/tools/builtin/index.d.ts +1 -0
- package/dist/tools/builtin/index.js +3 -0
- package/dist/tools/builtin/index.js.map +1 -1
- package/dist/tools/builtin/memory.d.ts +5 -5
- package/dist/tools/builtin/memory.js +151 -40
- package/dist/tools/builtin/memory.js.map +1 -1
- package/dist/tools/index.d.ts +2 -0
- package/dist/tools/index.js +1 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/questions.d.ts +89 -0
- package/dist/tools/questions.js +97 -0
- package/dist/tools/questions.js.map +1 -0
- package/dist/tools/types.d.ts +7 -0
- package/dist/tools/types.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { buildLinkGraph } from "./memory-links.js";
|
|
3
|
+
import { tokenize } from "./memory-recall.js";
|
|
4
|
+
/**
|
|
5
|
+
* Checks over a set of notes that need no model: what a person tidying up
|
|
6
|
+
* would want pointed out.
|
|
7
|
+
*
|
|
8
|
+
* Each finding carries a key made from the notes it is about, at their current
|
|
9
|
+
* hashes. Dismissing a finding stores the key, so the same finding stays
|
|
10
|
+
* hidden, and any edit to one of its notes brings it back as a new one.
|
|
11
|
+
*
|
|
12
|
+
* Only `duplicate` may ever be acted on without a person (AUTO_KINDS): a note
|
|
13
|
+
* nobody recalled lately, or one naming a file that moved, can still be right.
|
|
14
|
+
*/
|
|
15
|
+
export const REVIEW_KINDS = ["duplicate", "dangling", "stale-path", "unused", "oversized"];
|
|
16
|
+
export const AUTO_KINDS = new Set(["duplicate"]);
|
|
17
|
+
const DAY = 86_400_000;
|
|
18
|
+
const MAX_GROUP = 6;
|
|
19
|
+
/** A token in more notes than this says nothing about which notes are alike. */
|
|
20
|
+
const COMMON_TOKEN = 50;
|
|
21
|
+
const PATH = /(?:^|[\s`(\["'])((?:\.{1,2}\/)?(?:[\w@.-]+\/)+[\w@.-]+\.[a-zA-Z0-9]{1,8})(?=$|[\s`)\]"',:;])/gm;
|
|
22
|
+
const FENCE = /^(```|~~~)[^\n]*\n[\s\S]*?^\1[ \t]*$/gm;
|
|
23
|
+
const findingKey = (kind, scope, notes, detail) => `${kind}:${createHash("sha256").update(JSON.stringify([scope, notes.map((note) => [note.id, note.hash]), detail])).digest("hex").slice(0, 24)}`;
|
|
24
|
+
/** Paths a note names in prose, relative ones only. URLs and code blocks are skipped. */
|
|
25
|
+
export function mentionedPaths(body) {
|
|
26
|
+
const found = new Set();
|
|
27
|
+
for (const match of body.replace(FENCE, "").matchAll(PATH)) {
|
|
28
|
+
const candidate = match[1];
|
|
29
|
+
const before = body.slice(Math.max(0, match.index - 3), match.index + 1);
|
|
30
|
+
if (before.includes(":/") || candidate.includes("://"))
|
|
31
|
+
continue;
|
|
32
|
+
found.add(candidate.replace(/^\.\//, ""));
|
|
33
|
+
if (found.size >= 10)
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
return [...found];
|
|
37
|
+
}
|
|
38
|
+
function subjectTokens(note) {
|
|
39
|
+
return new Set([...tokenize(note.summary), ...note.tags.flatMap((tag) => tokenize(tag.replace(/[-:/.]/g, " ")))]);
|
|
40
|
+
}
|
|
41
|
+
/** Groups of notes in one scope that are about the same thing, by summary and tags. */
|
|
42
|
+
export function duplicateGroups(notes, threshold = 0.6) {
|
|
43
|
+
const tokens = notes.map(subjectTokens);
|
|
44
|
+
const normalized = notes.map((note) => note.summary.toLowerCase().replace(/[\s\p{P}]+/gu, " ").trim());
|
|
45
|
+
const byToken = new Map();
|
|
46
|
+
tokens.forEach((set, index) => { for (const token of set) {
|
|
47
|
+
const list = byToken.get(token) ?? [];
|
|
48
|
+
list.push(index);
|
|
49
|
+
byToken.set(token, list);
|
|
50
|
+
} });
|
|
51
|
+
const parent = notes.map((_, index) => index);
|
|
52
|
+
const find = (i) => { while (parent[i] !== i) {
|
|
53
|
+
parent[i] = parent[parent[i]];
|
|
54
|
+
i = parent[i];
|
|
55
|
+
} return i; };
|
|
56
|
+
for (let i = 0; i < notes.length; i++) {
|
|
57
|
+
const candidates = new Set();
|
|
58
|
+
for (const token of tokens[i]) {
|
|
59
|
+
const list = byToken.get(token);
|
|
60
|
+
if (list.length > COMMON_TOKEN)
|
|
61
|
+
continue;
|
|
62
|
+
for (const j of list)
|
|
63
|
+
if (j > i)
|
|
64
|
+
candidates.add(j);
|
|
65
|
+
}
|
|
66
|
+
for (let j = i + 1; j < notes.length; j++)
|
|
67
|
+
if (normalized[i] && normalized[i] === normalized[j])
|
|
68
|
+
candidates.add(j);
|
|
69
|
+
for (const j of candidates) {
|
|
70
|
+
if (notes[i].scope !== notes[j].scope)
|
|
71
|
+
continue;
|
|
72
|
+
const a = tokens[i], b = tokens[j];
|
|
73
|
+
let shared = 0;
|
|
74
|
+
for (const token of a)
|
|
75
|
+
if (b.has(token))
|
|
76
|
+
shared++;
|
|
77
|
+
const union = a.size + b.size - shared;
|
|
78
|
+
const same = normalized[i] !== "" && normalized[i] === normalized[j];
|
|
79
|
+
if (same || (a.size >= 2 && b.size >= 2 && union > 0 && shared / union >= threshold))
|
|
80
|
+
parent[find(i)] = find(j);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const groups = new Map();
|
|
84
|
+
notes.forEach((note, index) => { const root = find(index); groups.set(root, [...(groups.get(root) ?? []), note]); });
|
|
85
|
+
return [...groups.values()]
|
|
86
|
+
.filter((group) => group.length > 1)
|
|
87
|
+
.map((group) => [...group].sort((a, b) => a.createdAt - b.createdAt || a.id.localeCompare(b.id)).slice(0, MAX_GROUP));
|
|
88
|
+
}
|
|
89
|
+
export function reviewNotes(notes, options = {}) {
|
|
90
|
+
const now = options.now ?? Date.now();
|
|
91
|
+
const dismissed = options.dismissed ?? new Set();
|
|
92
|
+
const findings = [];
|
|
93
|
+
const push = (kind, scope, group, detail = []) => {
|
|
94
|
+
const key = findingKey(kind, scope, group, detail);
|
|
95
|
+
if (!dismissed.has(key))
|
|
96
|
+
findings.push({ key, kind, scope, ids: group.map((note) => note.id), detail });
|
|
97
|
+
};
|
|
98
|
+
for (const group of duplicateGroups(notes, options.duplicateThreshold))
|
|
99
|
+
push("duplicate", group[0].scope, group);
|
|
100
|
+
const graph = buildLinkGraph(notes);
|
|
101
|
+
for (const note of notes) {
|
|
102
|
+
const missing = graph.dangling.get(note.id);
|
|
103
|
+
if (missing?.length)
|
|
104
|
+
push("dangling", note.scope, [note], missing);
|
|
105
|
+
}
|
|
106
|
+
if (options.pathExists) {
|
|
107
|
+
for (const note of notes) {
|
|
108
|
+
if (note.scope !== "project")
|
|
109
|
+
continue;
|
|
110
|
+
const missing = mentionedPaths(note.body).filter((one) => !options.pathExists(one));
|
|
111
|
+
if (missing.length)
|
|
112
|
+
push("stale-path", note.scope, [note], missing);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
const unusedMs = (options.unusedDays ?? 90) * DAY;
|
|
116
|
+
for (const note of notes) {
|
|
117
|
+
const last = Math.max(options.usage?.(note.scope, note.id)?.last ?? 0, note.updatedAt ?? note.createdAt);
|
|
118
|
+
if (now - last > unusedMs)
|
|
119
|
+
push("unused", note.scope, [note]);
|
|
120
|
+
}
|
|
121
|
+
const oversized = options.oversizedChars ?? 8_000;
|
|
122
|
+
for (const note of notes)
|
|
123
|
+
if (note.body.length > oversized)
|
|
124
|
+
push("oversized", note.scope, [note]);
|
|
125
|
+
return findings;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=memory-review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-review.js","sourceRoot":"","sources":["../../src/agent/memory-review.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How often each note has been recalled, on this machine only.
|
|
3
|
+
*
|
|
4
|
+
* Kept outside the note files: writing a counter into a note would make every
|
|
5
|
+
* recall an edit, and every edit a sync upload.
|
|
6
|
+
*/
|
|
7
|
+
export interface UsageRecord {
|
|
8
|
+
count: number;
|
|
9
|
+
last: number;
|
|
10
|
+
}
|
|
11
|
+
export declare class MemoryUsage {
|
|
12
|
+
private readonly file;
|
|
13
|
+
private records?;
|
|
14
|
+
private pending?;
|
|
15
|
+
private writing;
|
|
16
|
+
constructor(directory: string);
|
|
17
|
+
private load;
|
|
18
|
+
get(id: string): UsageRecord | undefined;
|
|
19
|
+
record(ids: readonly string[], now?: number): void;
|
|
20
|
+
/** Drop records for notes that no longer exist. */
|
|
21
|
+
prune(existing: ReadonlySet<string>): void;
|
|
22
|
+
private schedule;
|
|
23
|
+
flush(): Promise<void>;
|
|
24
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { readUserFile, writeUserFile } from "../config-files.js";
|
|
4
|
+
export class MemoryUsage {
|
|
5
|
+
file;
|
|
6
|
+
records;
|
|
7
|
+
pending;
|
|
8
|
+
writing = Promise.resolve();
|
|
9
|
+
constructor(directory) {
|
|
10
|
+
const key = createHash("sha256").update(path.resolve(directory)).digest("hex").slice(0, 32);
|
|
11
|
+
this.file = `memory-usage/${key}.json`;
|
|
12
|
+
}
|
|
13
|
+
load() {
|
|
14
|
+
if (this.records)
|
|
15
|
+
return this.records;
|
|
16
|
+
try {
|
|
17
|
+
const raw = readUserFile(this.file);
|
|
18
|
+
this.records = raw?.notes && typeof raw.notes === "object" ? raw.notes : {};
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
this.records = {};
|
|
22
|
+
}
|
|
23
|
+
return this.records;
|
|
24
|
+
}
|
|
25
|
+
get(id) {
|
|
26
|
+
const record = this.load()[id];
|
|
27
|
+
return record && typeof record.count === "number" ? record : undefined;
|
|
28
|
+
}
|
|
29
|
+
record(ids, now = Date.now()) {
|
|
30
|
+
if (!ids.length)
|
|
31
|
+
return;
|
|
32
|
+
const records = this.load();
|
|
33
|
+
for (const id of ids) {
|
|
34
|
+
const previous = records[id];
|
|
35
|
+
records[id] = { count: (previous?.count ?? 0) + 1, last: now };
|
|
36
|
+
}
|
|
37
|
+
this.schedule();
|
|
38
|
+
}
|
|
39
|
+
/** Drop records for notes that no longer exist. */
|
|
40
|
+
prune(existing) {
|
|
41
|
+
const records = this.load();
|
|
42
|
+
let changed = false;
|
|
43
|
+
for (const id of Object.keys(records)) {
|
|
44
|
+
if (!existing.has(id)) {
|
|
45
|
+
delete records[id];
|
|
46
|
+
changed = true;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (changed)
|
|
50
|
+
this.schedule();
|
|
51
|
+
}
|
|
52
|
+
schedule() {
|
|
53
|
+
if (this.pending)
|
|
54
|
+
return;
|
|
55
|
+
this.pending = setTimeout(() => { this.pending = undefined; void this.flush(); }, 1_000);
|
|
56
|
+
this.pending.unref?.();
|
|
57
|
+
}
|
|
58
|
+
flush() {
|
|
59
|
+
if (this.pending) {
|
|
60
|
+
clearTimeout(this.pending);
|
|
61
|
+
this.pending = undefined;
|
|
62
|
+
}
|
|
63
|
+
const snapshot = { notes: { ...this.load() } };
|
|
64
|
+
this.writing = this.writing.then(() => writeUserFile(this.file, snapshot)).catch(() => { });
|
|
65
|
+
return this.writing;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=memory-usage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-usage.js","sourceRoot":"","sources":["../../src/agent/memory-usage.ts"],"names":[],"mappings":"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"}
|
package/dist/agent/memory.d.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import type { MemoryRecallPolicy, MemoryScope, MemoryType } from "./memory-limits.ts";
|
|
2
|
+
import type { LinkGraph } from "./memory-links.ts";
|
|
3
|
+
import type { Ranked, RankOptions, RecallNote } from "./memory-recall.ts";
|
|
4
|
+
import type { MemoryUsage } from "./memory-usage.ts";
|
|
5
|
+
import type { MemoryRecallInput, MemoryRecallResult } from "./memory-provider.ts";
|
|
6
|
+
export type { MemoryScope, MemoryType } from "./memory-limits.ts";
|
|
1
7
|
/**
|
|
2
8
|
* Durable lessons the agent writes for its future self.
|
|
3
9
|
*
|
|
@@ -7,48 +13,165 @@
|
|
|
7
13
|
*
|
|
8
14
|
* One fact per file, deliberately. A single growing notes file gets rewritten
|
|
9
15
|
* wholesale on every update, which loses entries to careless edits and makes
|
|
10
|
-
* "what changed" unanswerable
|
|
16
|
+
* "what changed" unanswerable — and it is what lets cloud sync reconcile note
|
|
17
|
+
* by note instead of file against file.
|
|
11
18
|
*/
|
|
12
19
|
export interface MemoryEntry {
|
|
13
20
|
id: string;
|
|
14
|
-
/** One line, shown in the prompt index. */
|
|
21
|
+
/** One line, shown in the prompt index and matched by recall. */
|
|
15
22
|
summary: string;
|
|
16
23
|
/** The full note. */
|
|
17
24
|
body: string;
|
|
18
25
|
/** Free-form tags for retrieval. */
|
|
19
26
|
tags: string[];
|
|
27
|
+
/** What kind of fact this is. Notes written before types existed have none. */
|
|
28
|
+
type?: MemoryType;
|
|
20
29
|
createdAt: number;
|
|
21
30
|
updatedAt?: number;
|
|
22
31
|
file: string;
|
|
23
32
|
}
|
|
24
33
|
export type MemoryNote = Omit<MemoryEntry, "file">;
|
|
25
34
|
export declare const validMemoryId: (id: unknown) => id is string;
|
|
35
|
+
/**
|
|
36
|
+
* The identity of a note's content, compared across machines.
|
|
37
|
+
*
|
|
38
|
+
* `type` takes part only when a note has one. Every note written before the
|
|
39
|
+
* field existed keeps exactly the hash that its sync baseline and the server's
|
|
40
|
+
* manifest already recorded; including an absent type as `null` would have
|
|
41
|
+
* made every existing note look edited on every machine at once.
|
|
42
|
+
*/
|
|
26
43
|
export declare function noteHash(note: MemoryNote | undefined): string | null;
|
|
44
|
+
/**
|
|
45
|
+
* Tags as a model writes them, made into tags a note can hold.
|
|
46
|
+
*
|
|
47
|
+
* Models pad them (" aesthetics"), prefix them ("#design"), and put two in one
|
|
48
|
+
* string ("design, ux"). Refusing the whole note over that loses a note the
|
|
49
|
+
* user asked for, so each is trimmed, split and de-duplicated, and anything
|
|
50
|
+
* still unusable is dropped.
|
|
51
|
+
*/
|
|
52
|
+
export declare function normalizeTags(tags: readonly unknown[]): string[];
|
|
27
53
|
export declare function memoryNote(entry: MemoryEntry): MemoryNote;
|
|
28
|
-
export declare function validateNote(note: MemoryNote): void;
|
|
54
|
+
export declare function validateNote(note: MemoryNote, maxNoteBytes?: number): void;
|
|
55
|
+
/** `sync` is a write a pull applied; every other write is `local`. */
|
|
56
|
+
export type MemoryWriteOrigin = "local" | "sync";
|
|
57
|
+
export interface MemoryChange {
|
|
58
|
+
id: string;
|
|
59
|
+
origin: MemoryWriteOrigin;
|
|
60
|
+
}
|
|
61
|
+
export interface MemoryStoreOptions {
|
|
62
|
+
/** Past this many files, only the most recently modified are loaded. */
|
|
63
|
+
maxNotes?: number;
|
|
64
|
+
maxNoteBytes?: number;
|
|
65
|
+
/** Which scope this directory holds; carried onto recall results. */
|
|
66
|
+
scope?: MemoryScope;
|
|
67
|
+
/** Told once per distinct condition worth a person's attention, such as notes left unloaded. */
|
|
68
|
+
onWarning?(message: string): void;
|
|
69
|
+
}
|
|
70
|
+
export interface MemorySnapshot {
|
|
71
|
+
entries: MemoryEntry[];
|
|
72
|
+
/** Notes present on disk but not loaded because the directory is over its limit. */
|
|
73
|
+
omitted: number;
|
|
74
|
+
links: LinkGraph;
|
|
75
|
+
}
|
|
76
|
+
/** A note as recall and the tools see it: its scope, and the entry behind it. */
|
|
77
|
+
export type ScopedNote = RecallNote & {
|
|
78
|
+
entry: MemoryEntry;
|
|
79
|
+
};
|
|
29
80
|
export declare class MemoryStore {
|
|
30
81
|
private readonly dir;
|
|
31
|
-
|
|
82
|
+
readonly maxNotes: number;
|
|
83
|
+
readonly maxNoteBytes: number;
|
|
84
|
+
readonly scope: MemoryScope;
|
|
85
|
+
private readonly onWarning?;
|
|
86
|
+
private files;
|
|
87
|
+
private cached?;
|
|
88
|
+
private warnedOmitted;
|
|
89
|
+
private readonly scoped;
|
|
90
|
+
private readonly listeners;
|
|
91
|
+
constructor(dir: string, options?: MemoryStoreOptions);
|
|
32
92
|
get location(): string;
|
|
93
|
+
/** Told after every write this store makes, once the file is in place. */
|
|
94
|
+
onChange(listener: (change: MemoryChange) => void): () => void;
|
|
95
|
+
private emit;
|
|
33
96
|
load(): Promise<MemoryEntry[]>;
|
|
97
|
+
/**
|
|
98
|
+
* Every note, read from disk only where a file changed.
|
|
99
|
+
*
|
|
100
|
+
* Recall scores notes on every user message, so rereading the directory each
|
|
101
|
+
* time would put thousands of file reads in front of every reply. A file's
|
|
102
|
+
* size and timestamps decide whether its parsed note is reused; the store's
|
|
103
|
+
* own writes drop their file from that cache outright, because two writes
|
|
104
|
+
* inside one timestamp tick with bodies of equal length would otherwise look
|
|
105
|
+
* unchanged.
|
|
106
|
+
*/
|
|
107
|
+
snapshot(): Promise<MemorySnapshot>;
|
|
108
|
+
private readNote;
|
|
109
|
+
/**
|
|
110
|
+
* Write a note. With `id`, that note is updated and must exist. Without it,
|
|
111
|
+
* a note whose summary matches (ignoring case) is updated rather than
|
|
112
|
+
* duplicated, and otherwise a new one is created.
|
|
113
|
+
*/
|
|
34
114
|
remember(input: {
|
|
35
115
|
summary: string;
|
|
36
116
|
body: string;
|
|
37
117
|
tags?: string[];
|
|
118
|
+
type?: MemoryType;
|
|
119
|
+
id?: string;
|
|
38
120
|
}): Promise<MemoryEntry>;
|
|
39
121
|
forget(id: string): Promise<boolean>;
|
|
40
122
|
/** Compare before applying downloaded data; never overwrite a concurrent edit. */
|
|
41
|
-
apply(id: string, note: MemoryNote | undefined, expected: string | null): Promise<void>;
|
|
123
|
+
apply(id: string, note: MemoryNote | undefined, expected: string | null, origin?: MemoryWriteOrigin): Promise<void>;
|
|
42
124
|
private exclusive;
|
|
125
|
+
private invalidate;
|
|
43
126
|
private atomic;
|
|
44
|
-
/**
|
|
127
|
+
/** Notes as recall sees them, with this store's scope. Stable objects while a file is unchanged. */
|
|
128
|
+
scopedNotes(entries: readonly MemoryEntry[]): ScopedNote[];
|
|
129
|
+
/** Notes scored against a query, best first. */
|
|
130
|
+
rank(query: string, options?: RankOptions): Promise<Ranked<ScopedNote>[]>;
|
|
131
|
+
/** Scored search across summaries, bodies and tags, falling back to plain substring matching. */
|
|
45
132
|
search(query: string): Promise<MemoryEntry[]>;
|
|
46
|
-
/**
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
133
|
+
/** The index for this store alone. See `memoryIndexSection`. */
|
|
134
|
+
promptSection(indexChars?: number): Promise<string | undefined>;
|
|
135
|
+
}
|
|
136
|
+
/** Project and user notes together. The user store is absent when its directory could not be created. */
|
|
137
|
+
export interface MemoryStores {
|
|
138
|
+
project: MemoryStore;
|
|
139
|
+
user?: MemoryStore;
|
|
140
|
+
}
|
|
141
|
+
export interface ScopedMemory {
|
|
142
|
+
notes: ScopedNote[];
|
|
143
|
+
links: LinkGraph;
|
|
144
|
+
omitted: number;
|
|
54
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Both scopes loaded as one list, project notes first, with links resolved
|
|
148
|
+
* across the two: a note in either may link to a note in the other.
|
|
149
|
+
*/
|
|
150
|
+
export declare function loadScoped(stores: MemoryStores): Promise<ScopedMemory>;
|
|
151
|
+
/** A note by id, project scope first. */
|
|
152
|
+
export declare function findScoped(notes: readonly ScopedNote[], id: string): ScopedNote | undefined;
|
|
153
|
+
export declare function storeFor(stores: MemoryStores, scope: MemoryScope): MemoryStore;
|
|
154
|
+
export declare const MEMORY_GUIDANCE: string;
|
|
155
|
+
/**
|
|
156
|
+
* The index that goes into the system prompt: one line per note, summaries only.
|
|
157
|
+
*
|
|
158
|
+
* Same reasoning as skills — putting every note's body in the prompt would
|
|
159
|
+
* grow without bound and crowd out the actual conversation. The model reads a
|
|
160
|
+
* summary, then asks for the body if it matters; notes that match a message
|
|
161
|
+
* are attached to it without being asked for.
|
|
162
|
+
*
|
|
163
|
+
* Most recently touched first, which is not the order the notes are stored in.
|
|
164
|
+
* The budget drops whatever does not fit, so this ordering decides which notes
|
|
165
|
+
* stop being listed once there are more than about fifty. A note written a year
|
|
166
|
+
* ago and corrected on Tuesday is the more useful of the two, and updatedAt is
|
|
167
|
+
* the only thing here that knows that. Nothing is lost, only unlisted: the line
|
|
168
|
+
* at the end says how many, and the tool searches every note.
|
|
169
|
+
*/
|
|
170
|
+
export declare function memoryIndexSection(notes: readonly ScopedNote[], indexChars: number, options: {
|
|
171
|
+
showScope: boolean;
|
|
172
|
+
}): string | undefined;
|
|
173
|
+
/** Recall across both scopes, rendered for attaching to a user message. */
|
|
174
|
+
export declare function recallFromStores(stores: MemoryStores, input: MemoryRecallInput, policy: MemoryRecallPolicy, usage?: {
|
|
175
|
+
project?: MemoryUsage;
|
|
176
|
+
user?: MemoryUsage;
|
|
177
|
+
}): Promise<MemoryRecallResult | undefined>;
|