@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,38 @@
|
|
|
1
|
+
import type { MemoryScope } from "./memory-limits.ts";
|
|
2
|
+
import type { MemoryNote, MemoryStore, MemoryStores } from "./memory.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Copies of notes kept before anything replaces or removes them.
|
|
5
|
+
*
|
|
6
|
+
* Every path that makes a note disappear or changes it without the user
|
|
7
|
+
* looking writes one first: deleting from the page, `forget`, taking the cloud
|
|
8
|
+
* side of a conflict, an automatic pull, an extractor's rewrite, and a restore
|
|
9
|
+
* replacing a newer version. They live on this machine only, under
|
|
10
|
+
* `memory-backups/` in the user directory.
|
|
11
|
+
*/
|
|
12
|
+
export declare const BACKUP_REASONS: readonly ["delete", "forget", "conflict", "conflict-cloud", "auto-merge", "sync-update", "sync-delete", "extract-update", "consolidate", "restore"];
|
|
13
|
+
export type BackupReason = (typeof BACKUP_REASONS)[number];
|
|
14
|
+
export interface MemoryBackup {
|
|
15
|
+
/** File name inside the backups directory; what a restore names. */
|
|
16
|
+
file: string;
|
|
17
|
+
/** Absent on backups written before reasons were recorded. */
|
|
18
|
+
reason?: BackupReason;
|
|
19
|
+
scope?: MemoryScope;
|
|
20
|
+
/** The notes directory the note was in. */
|
|
21
|
+
location?: string;
|
|
22
|
+
backedUpAt: number;
|
|
23
|
+
note: MemoryNote;
|
|
24
|
+
}
|
|
25
|
+
export declare function backupNote(store: MemoryStore, note: MemoryNote, reason: BackupReason): Promise<string>;
|
|
26
|
+
/** The most recent backups, newest first. Unreadable files are skipped. */
|
|
27
|
+
export declare function listBackups(limit?: number): Promise<MemoryBackup[]>;
|
|
28
|
+
/**
|
|
29
|
+
* Put a backed-up note back where it came from.
|
|
30
|
+
*
|
|
31
|
+
* The directory it was in when that is still one of `stores`, then its scope,
|
|
32
|
+
* then the project. A newer version of the same note is backed up before being
|
|
33
|
+
* replaced, so a restore can itself be undone. The backup file is kept.
|
|
34
|
+
*/
|
|
35
|
+
export declare function restoreBackup(stores: MemoryStores, file: string): Promise<{
|
|
36
|
+
id: string;
|
|
37
|
+
scope: MemoryScope;
|
|
38
|
+
}>;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
2
|
+
import { lstat, readdir, readFile } from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { writeUserFile } from "../config-files.js";
|
|
5
|
+
import { userPath } from "../paths.js";
|
|
6
|
+
import { MEMORY_SAFETY, isMemoryScope } from "./memory-limits.js";
|
|
7
|
+
import { memoryNote, noteHash, validateNote } from "./memory.js";
|
|
8
|
+
/**
|
|
9
|
+
* Copies of notes kept before anything replaces or removes them.
|
|
10
|
+
*
|
|
11
|
+
* Every path that makes a note disappear or changes it without the user
|
|
12
|
+
* looking writes one first: deleting from the page, `forget`, taking the cloud
|
|
13
|
+
* side of a conflict, an automatic pull, an extractor's rewrite, and a restore
|
|
14
|
+
* replacing a newer version. They live on this machine only, under
|
|
15
|
+
* `memory-backups/` in the user directory.
|
|
16
|
+
*/
|
|
17
|
+
export const BACKUP_REASONS = ["delete", "forget", "conflict", "conflict-cloud", "auto-merge", "sync-update", "sync-delete", "extract-update", "consolidate", "restore"];
|
|
18
|
+
const DIRECTORY = "memory-backups";
|
|
19
|
+
const FILE = /^[a-zA-Z0-9_-]{1,160}\.json$/;
|
|
20
|
+
const MAX_FILE_BYTES = 2 * 1024 * 1024;
|
|
21
|
+
const object = (x) => !!x && typeof x === "object" && !Array.isArray(x);
|
|
22
|
+
export async function backupNote(store, note, reason) {
|
|
23
|
+
const at = Date.now();
|
|
24
|
+
const file = `${at}-${createHash("sha256").update(`${store.location}\0${note.id}\0${randomUUID()}`).digest("hex").slice(0, 16)}.json`;
|
|
25
|
+
await writeUserFile(`${DIRECTORY}/${file}`, {
|
|
26
|
+
version: 1, reason, scope: store.scope, location: store.location, backedUpAt: at, note: clean(note),
|
|
27
|
+
});
|
|
28
|
+
return file;
|
|
29
|
+
}
|
|
30
|
+
function clean(note) {
|
|
31
|
+
return {
|
|
32
|
+
id: note.id, summary: note.summary, body: note.body, tags: [...note.tags], createdAt: note.createdAt,
|
|
33
|
+
...(note.updatedAt ? { updatedAt: note.updatedAt } : {}),
|
|
34
|
+
...(note.type ? { type: note.type } : {}),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Backups in either format: the current wrapped one, or the bare note written before it. */
|
|
38
|
+
function parse(file, raw, mtimeMs) {
|
|
39
|
+
let value;
|
|
40
|
+
try {
|
|
41
|
+
value = JSON.parse(raw);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
46
|
+
if (!object(value))
|
|
47
|
+
return undefined;
|
|
48
|
+
const wrapped = value.version === 1 && object(value.note);
|
|
49
|
+
const note = (wrapped ? value.note : value);
|
|
50
|
+
try {
|
|
51
|
+
validateNote(note, MEMORY_SAFETY.maxNoteBytesCeiling);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
file,
|
|
58
|
+
backedUpAt: wrapped && Number.isSafeInteger(value.backedUpAt) ? value.backedUpAt : Math.floor(mtimeMs),
|
|
59
|
+
note: clean(note),
|
|
60
|
+
...(wrapped && BACKUP_REASONS.includes(value.reason) ? { reason: value.reason } : {}),
|
|
61
|
+
...(wrapped && isMemoryScope(value.scope) ? { scope: value.scope } : {}),
|
|
62
|
+
...(wrapped && typeof value.location === "string" ? { location: value.location } : {}),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/** The most recent backups, newest first. Unreadable files are skipped. */
|
|
66
|
+
export async function listBackups(limit = 100) {
|
|
67
|
+
const directory = userPath(DIRECTORY);
|
|
68
|
+
let names;
|
|
69
|
+
try {
|
|
70
|
+
names = (await readdir(directory)).filter((name) => FILE.test(name));
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return [];
|
|
74
|
+
}
|
|
75
|
+
const stats = (await Promise.all(names.map(async (name) => {
|
|
76
|
+
try {
|
|
77
|
+
const info = await lstat(path.join(directory, name));
|
|
78
|
+
return info.isFile() && info.size <= MAX_FILE_BYTES ? { name, mtimeMs: info.mtimeMs } : undefined;
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
}))).filter((item) => item !== undefined);
|
|
84
|
+
stats.sort((a, b) => b.mtimeMs - a.mtimeMs || b.name.localeCompare(a.name));
|
|
85
|
+
const backups = [];
|
|
86
|
+
for (const item of stats) {
|
|
87
|
+
if (backups.length >= limit)
|
|
88
|
+
break;
|
|
89
|
+
const raw = await readFile(path.join(directory, item.name), "utf8").catch(() => undefined);
|
|
90
|
+
const backup = raw === undefined ? undefined : parse(item.name, raw, item.mtimeMs);
|
|
91
|
+
if (backup)
|
|
92
|
+
backups.push(backup);
|
|
93
|
+
}
|
|
94
|
+
return backups.sort((a, b) => b.backedUpAt - a.backedUpAt);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Put a backed-up note back where it came from.
|
|
98
|
+
*
|
|
99
|
+
* The directory it was in when that is still one of `stores`, then its scope,
|
|
100
|
+
* then the project. A newer version of the same note is backed up before being
|
|
101
|
+
* replaced, so a restore can itself be undone. The backup file is kept.
|
|
102
|
+
*/
|
|
103
|
+
export async function restoreBackup(stores, file) {
|
|
104
|
+
if (!FILE.test(file))
|
|
105
|
+
throw new Error("Invalid backup file");
|
|
106
|
+
const full = path.join(userPath(DIRECTORY), file);
|
|
107
|
+
const info = await lstat(full).catch(() => undefined);
|
|
108
|
+
if (!info?.isFile() || info.size > MAX_FILE_BYTES)
|
|
109
|
+
throw new Error("Invalid backup file");
|
|
110
|
+
const backup = parse(file, await readFile(full, "utf8"), info.mtimeMs);
|
|
111
|
+
if (!backup)
|
|
112
|
+
throw new Error("Backup cannot be read");
|
|
113
|
+
const store = stores.user && backup.location === stores.user.location ? stores.user
|
|
114
|
+
: backup.location === stores.project.location ? stores.project
|
|
115
|
+
: backup.scope === "user" && stores.user ? stores.user
|
|
116
|
+
: stores.project;
|
|
117
|
+
const current = (await store.load()).find((entry) => entry.id === backup.note.id);
|
|
118
|
+
const currentNote = current ? memoryNote(current) : undefined;
|
|
119
|
+
if (currentNote && noteHash(currentNote) === noteHash(backup.note))
|
|
120
|
+
return { id: backup.note.id, scope: store.scope };
|
|
121
|
+
if (currentNote)
|
|
122
|
+
await backupNote(store, currentNote, "restore");
|
|
123
|
+
await store.apply(backup.note.id, { ...backup.note, updatedAt: Date.now() }, noteHash(currentNote));
|
|
124
|
+
return { id: backup.note.id, scope: store.scope };
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=memory-backup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-backup.js","sourceRoot":"","sources":["../../src/agent/memory-backup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { MemoryScope, MemoryType } from "./memory-limits.ts";
|
|
2
|
+
import type { MemoryNote } from "./memory.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Merging notes that say the same thing into one.
|
|
5
|
+
*
|
|
6
|
+
* The model only writes the combined text. Which notes go, which one stays,
|
|
7
|
+
* and how links elsewhere follow are decided here, by code that can be tested:
|
|
8
|
+
* the kept note is the oldest, so an id other notes and transcripts already
|
|
9
|
+
* cite keeps working, and every `[[removed]]` link in the scope is pointed at it.
|
|
10
|
+
*/
|
|
11
|
+
export interface MergeDraft {
|
|
12
|
+
summary: string;
|
|
13
|
+
body: string;
|
|
14
|
+
tags: string[];
|
|
15
|
+
type?: MemoryType;
|
|
16
|
+
}
|
|
17
|
+
export type ScopedMemoryNote = MemoryNote & {
|
|
18
|
+
scope: MemoryScope;
|
|
19
|
+
};
|
|
20
|
+
/** One write of a merge. `expectedHash` is the version the plan was made from. */
|
|
21
|
+
export interface MergeEdit {
|
|
22
|
+
scope: MemoryScope;
|
|
23
|
+
id: string;
|
|
24
|
+
note?: MemoryNote;
|
|
25
|
+
expectedHash: string | null;
|
|
26
|
+
}
|
|
27
|
+
export declare const CONSOLIDATE_PROMPT = "You merge notes an assistant keeps across sessions. The notes you are given overlap. Write one note that keeps every distinct fact, instruction and caveat from all of them, drops repetition, and never adds anything that is not in them. Where two notes contradict each other, keep both statements and say which is newer by the updated time given.\n\nKeep [[id]] links that appear in the notes. Do not invent links.\n\nReply with only a JSON object:\n{\"summary\": \"one line, under 150 characters, naming what the note is about\", \"body\": \"the merged note, Markdown\", \"tags\": [\"lowercase\", \"synonyms\"], \"type\": \"user|feedback|project|reference\"}";
|
|
28
|
+
export declare function mergePrompt(notes: readonly MemoryNote[]): string;
|
|
29
|
+
/** The model's reply as a draft, or undefined when it is not one. */
|
|
30
|
+
export declare function parseMergeReply(reply: string): MergeDraft | undefined;
|
|
31
|
+
/** A starting point for merging by hand: the oldest summary, every body, every tag. */
|
|
32
|
+
export declare function draftByHand(notes: readonly MemoryNote[]): MergeDraft;
|
|
33
|
+
/** Point `[[old]]` links at their new targets. */
|
|
34
|
+
export declare function rewriteLinks(body: string, targets: ReadonlyMap<string, string>): string;
|
|
35
|
+
/**
|
|
36
|
+
* Every write a merge makes: the kept note replaced by the draft, the others
|
|
37
|
+
* deleted, and notes in either scope that linked to a deleted one relinked.
|
|
38
|
+
* `ids` are merged in the order given; the first is kept.
|
|
39
|
+
*/
|
|
40
|
+
export declare function planMerge(input: {
|
|
41
|
+
all: readonly ScopedMemoryNote[];
|
|
42
|
+
scope: MemoryScope;
|
|
43
|
+
ids: readonly string[];
|
|
44
|
+
draft: MergeDraft;
|
|
45
|
+
hash(note: MemoryNote): string | null;
|
|
46
|
+
now?: number;
|
|
47
|
+
}): MergeEdit[];
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { MemoryError } from "./memory-errors.js";
|
|
2
|
+
import { MEMORY_SAFETY, isMemoryType } from "./memory-limits.js";
|
|
3
|
+
import { redactSecrets } from "./memory-redact.js";
|
|
4
|
+
export const CONSOLIDATE_PROMPT = `You merge notes an assistant keeps across sessions. The notes you are given overlap. Write one note that keeps every distinct fact, instruction and caveat from all of them, drops repetition, and never adds anything that is not in them. Where two notes contradict each other, keep both statements and say which is newer by the updated time given.
|
|
5
|
+
|
|
6
|
+
Keep [[id]] links that appear in the notes. Do not invent links.
|
|
7
|
+
|
|
8
|
+
Reply with only a JSON object:
|
|
9
|
+
{"summary": "one line, under 150 characters, naming what the note is about", "body": "the merged note, Markdown", "tags": ["lowercase", "synonyms"], "type": "user|feedback|project|reference"}`;
|
|
10
|
+
export function mergePrompt(notes) {
|
|
11
|
+
const blocks = notes.map((note) => {
|
|
12
|
+
const when = new Date(note.updatedAt ?? note.createdAt).toISOString();
|
|
13
|
+
const meta = [`id=${note.id}`, `updated=${when}`, note.type ? `type=${note.type}` : "", note.tags.length ? `tags=${note.tags.join(",")}` : ""].filter(Boolean).join(" ");
|
|
14
|
+
return `<note ${meta}>\n${note.summary}\n\n${note.body}\n</note>`;
|
|
15
|
+
});
|
|
16
|
+
return `Notes to merge:\n\n${blocks.join("\n\n")}\n\nReply with the merged note as JSON now.`;
|
|
17
|
+
}
|
|
18
|
+
function cleanTags(tags) {
|
|
19
|
+
if (!Array.isArray(tags))
|
|
20
|
+
return [];
|
|
21
|
+
const out = [];
|
|
22
|
+
for (const tag of tags) {
|
|
23
|
+
if (typeof tag !== "string")
|
|
24
|
+
continue;
|
|
25
|
+
const value = tag.trim().toLowerCase();
|
|
26
|
+
if (MEMORY_SAFETY.tagPattern.test(value) && !out.includes(value))
|
|
27
|
+
out.push(value);
|
|
28
|
+
if (out.length >= MEMORY_SAFETY.maxTags)
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
return out;
|
|
32
|
+
}
|
|
33
|
+
/** The model's reply as a draft, or undefined when it is not one. */
|
|
34
|
+
export function parseMergeReply(reply) {
|
|
35
|
+
const start = reply.indexOf("{"), end = reply.lastIndexOf("}");
|
|
36
|
+
if (start < 0 || end <= start)
|
|
37
|
+
return undefined;
|
|
38
|
+
let value;
|
|
39
|
+
try {
|
|
40
|
+
value = JSON.parse(reply.slice(start, end + 1));
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
if (!value || typeof value !== "object")
|
|
46
|
+
return undefined;
|
|
47
|
+
const raw = value;
|
|
48
|
+
const summary = typeof raw.summary === "string" ? raw.summary.replace(/[\r\n]+/g, " ").trim().slice(0, MEMORY_SAFETY.maxSummaryChars) : "";
|
|
49
|
+
const body = typeof raw.body === "string" ? redactSecrets(raw.body).text.trim() : "";
|
|
50
|
+
if (!summary || !body)
|
|
51
|
+
return undefined;
|
|
52
|
+
return { summary: redactSecrets(summary).text, body, tags: cleanTags(raw.tags), ...(isMemoryType(raw.type) ? { type: raw.type } : {}) };
|
|
53
|
+
}
|
|
54
|
+
/** A starting point for merging by hand: the oldest summary, every body, every tag. */
|
|
55
|
+
export function draftByHand(notes) {
|
|
56
|
+
const first = notes[0];
|
|
57
|
+
const bodies = [];
|
|
58
|
+
for (const note of notes)
|
|
59
|
+
if (!bodies.includes(note.body))
|
|
60
|
+
bodies.push(note.body);
|
|
61
|
+
return {
|
|
62
|
+
summary: first.summary,
|
|
63
|
+
body: bodies.join("\n\n"),
|
|
64
|
+
tags: cleanTags(notes.flatMap((note) => note.tags)),
|
|
65
|
+
...(first.type ? { type: first.type } : {}),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/** Point `[[old]]` links at their new targets. */
|
|
69
|
+
export function rewriteLinks(body, targets) {
|
|
70
|
+
return body.replace(/\[\[([a-zA-Z0-9_-]{1,128})\]\]/g, (whole, id) => {
|
|
71
|
+
const target = targets.get(id);
|
|
72
|
+
return target ? `[[${target}]]` : whole;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Every write a merge makes: the kept note replaced by the draft, the others
|
|
77
|
+
* deleted, and notes in either scope that linked to a deleted one relinked.
|
|
78
|
+
* `ids` are merged in the order given; the first is kept.
|
|
79
|
+
*/
|
|
80
|
+
export function planMerge(input) {
|
|
81
|
+
const group = input.ids.map((id) => input.all.find((note) => note.id === id && note.scope === input.scope));
|
|
82
|
+
if (group.length < 2 || group.some((note) => !note) || new Set(input.ids).size !== input.ids.length) {
|
|
83
|
+
throw new MemoryError("mergeGone");
|
|
84
|
+
}
|
|
85
|
+
const notes = group;
|
|
86
|
+
const keep = notes[0];
|
|
87
|
+
const targets = new Map(notes.slice(1).map((note) => [note.id, keep.id]));
|
|
88
|
+
const merged = {
|
|
89
|
+
id: keep.id,
|
|
90
|
+
summary: input.draft.summary,
|
|
91
|
+
body: rewriteLinks(input.draft.body, targets).trim(),
|
|
92
|
+
tags: [...input.draft.tags],
|
|
93
|
+
createdAt: Math.min(...notes.map((note) => note.createdAt)),
|
|
94
|
+
updatedAt: input.now ?? Date.now(),
|
|
95
|
+
};
|
|
96
|
+
if (input.draft.type)
|
|
97
|
+
merged.type = input.draft.type;
|
|
98
|
+
const edits = [
|
|
99
|
+
{ scope: input.scope, id: keep.id, note: merged, expectedHash: input.hash(stripScope(keep)) },
|
|
100
|
+
...notes.slice(1).map((note) => ({ scope: input.scope, id: note.id, expectedHash: input.hash(stripScope(note)) })),
|
|
101
|
+
];
|
|
102
|
+
// Only the scope a note is in holds its links to rewrite, so a user note
|
|
103
|
+
// linking into this project is relinked in the user scope.
|
|
104
|
+
for (const other of input.all) {
|
|
105
|
+
if (other.scope === input.scope && (other.id === keep.id || targets.has(other.id)))
|
|
106
|
+
continue;
|
|
107
|
+
const body = rewriteLinks(other.body, other.scope === input.scope ? targets : new Map());
|
|
108
|
+
if (body === other.body)
|
|
109
|
+
continue;
|
|
110
|
+
edits.push({ scope: other.scope, id: other.id, note: { ...stripScope(other), body, updatedAt: input.now ?? Date.now() }, expectedHash: input.hash(stripScope(other)) });
|
|
111
|
+
}
|
|
112
|
+
return edits;
|
|
113
|
+
}
|
|
114
|
+
function stripScope(note) {
|
|
115
|
+
const { scope: _scope, ...rest } = note;
|
|
116
|
+
return rest;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=memory-consolidate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-consolidate.js","sourceRoot":"","sources":["../../src/agent/memory-consolidate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Errors the memory subsystem shows to people, by code.
|
|
3
|
+
*
|
|
4
|
+
* The engine does not choose a language. The message here is an English
|
|
5
|
+
* default for callers with no strings of their own (logs, the terminal, a
|
|
6
|
+
* model reading a tool error); a frontend with its own strings translates by
|
|
7
|
+
* `code` and `params` instead, as the web page does with `memory.err.*`.
|
|
8
|
+
* Codes are stable. Wording may change.
|
|
9
|
+
*/
|
|
10
|
+
declare const MESSAGES: {
|
|
11
|
+
readonly configInvalid: "Memory sync settings are invalid, so sync has stopped.";
|
|
12
|
+
readonly stopped: "Memory sync has stopped.";
|
|
13
|
+
readonly disabledHere: "Cloud sync was turned off for these notes.";
|
|
14
|
+
readonly accountChanged: "The signed-in account or Cloud address changed, so memory sync is paused.";
|
|
15
|
+
readonly settingsChanged: "Memory sync settings changed.";
|
|
16
|
+
readonly localUnreadable: "Notes on this machine cannot be read or are invalid. Check the memory folder. Sync is paused and no file was changed.";
|
|
17
|
+
readonly signInFirst: "Sign in to OHarness first.";
|
|
18
|
+
readonly boundElsewhere: "This notes folder is already bound to another account or Cloud. Use a separate notes folder so notes are not uploaded across accounts.";
|
|
19
|
+
readonly verifyFailed: "Account verification failed.";
|
|
20
|
+
readonly syncFailed: "Sync failed.";
|
|
21
|
+
readonly invalidVersion: "The sync service returned an invalid version.";
|
|
22
|
+
readonly waitForSync: "Wait for the current sync to finish.";
|
|
23
|
+
readonly stale: "Notes changed on this machine or another device. Sync, then try again.";
|
|
24
|
+
readonly invalidBatch: "Invalid batch change.";
|
|
25
|
+
readonly batchTooLarge: "Too many notes changed at once. Change them in smaller batches.";
|
|
26
|
+
readonly serverTooOld: "The sync service is too old to sync your own notes. Upgrade the sync service.";
|
|
27
|
+
readonly accountSwitched: "The account changed.";
|
|
28
|
+
readonly invalidChoice: "Invalid conflict choice.";
|
|
29
|
+
readonly localChanged: "Notes on this machine changed. Sync again.";
|
|
30
|
+
readonly oneSideDeleted: "One side deleted this note, so both copies cannot be kept.";
|
|
31
|
+
readonly mergedMissing: "The merged note is missing.";
|
|
32
|
+
readonly secret: "The note seems to contain a credential, so it was not saved.";
|
|
33
|
+
readonly secretFound: "The note seems to contain a credential ({kinds}), so it was not saved.";
|
|
34
|
+
readonly mergedSecret: "The merged note seems to contain a credential, so it was not saved.";
|
|
35
|
+
readonly conflictsPending: "{count} notes were changed on both sides in overlapping ways and could not be merged automatically. Choose which version to keep. Everything else is synced.";
|
|
36
|
+
readonly conflictsRemain: "Some conflicts still need resolving.";
|
|
37
|
+
readonly invalidResponse: "The sync service returned invalid data.";
|
|
38
|
+
readonly signInAgain: "Sign in to OHarness again.";
|
|
39
|
+
readonly requestFailed: "The memory sync request failed or was cancelled. You can try again.";
|
|
40
|
+
readonly cloudChanged: "The cloud version changed. Sync again.";
|
|
41
|
+
readonly rateLimited: "Syncing too often. It will retry automatically.";
|
|
42
|
+
readonly serverNotConfigured: "The sync service has not set up memory sign-in or R2 storage.";
|
|
43
|
+
readonly quotaExceeded: "Over the sync service's memory quota.";
|
|
44
|
+
readonly rejected: "The sync request was refused. Check your account and sync settings.";
|
|
45
|
+
readonly planLimit: "Free cloud sync for memory is full: at most {notes} project notes and {notes} of your own, {kb} KB each. Upgrading removes these limits. Notes on this machine are not affected.";
|
|
46
|
+
readonly planLimitPlain: "Free cloud sync for memory is full. Upgrading removes the limits. Notes on this machine are not affected.";
|
|
47
|
+
readonly responseTooLarge: "The sync response was too large.";
|
|
48
|
+
readonly principalMismatch: "The sync response is for a different account.";
|
|
49
|
+
readonly mergeGone: "The notes to merge no longer exist or have changed.";
|
|
50
|
+
readonly modelNoDraft: "The model did not return a usable merge. You can merge by hand instead.";
|
|
51
|
+
readonly mergeStale: "Notes changed. Suggest the merge again.";
|
|
52
|
+
readonly editStale: "The note changed. Refresh, then edit again.";
|
|
53
|
+
readonly deleteStale: "The note changed. Refresh the page.";
|
|
54
|
+
readonly mergeEmpty: "The merged summary and body cannot be empty.";
|
|
55
|
+
readonly unknownAction: "Unknown memory action.";
|
|
56
|
+
};
|
|
57
|
+
export type MemoryErrorCode = keyof typeof MESSAGES;
|
|
58
|
+
export type MemoryErrorParams = Record<string, string | number>;
|
|
59
|
+
/** Every code and its English message, for frontends that check their strings cover them. */
|
|
60
|
+
export declare const MEMORY_ERROR_MESSAGES: Readonly<Record<MemoryErrorCode, string>>;
|
|
61
|
+
export declare class MemoryError extends Error {
|
|
62
|
+
readonly code: MemoryErrorCode;
|
|
63
|
+
readonly params: MemoryErrorParams;
|
|
64
|
+
constructor(code: MemoryErrorCode, params?: MemoryErrorParams);
|
|
65
|
+
}
|
|
66
|
+
/** What a status report carries about a failure: the message, and the code when there is one. */
|
|
67
|
+
export interface MemoryFailureInfo {
|
|
68
|
+
message: string;
|
|
69
|
+
code?: MemoryErrorCode;
|
|
70
|
+
params?: MemoryErrorParams;
|
|
71
|
+
}
|
|
72
|
+
export declare function memoryFailure(error: unknown): MemoryFailureInfo;
|
|
73
|
+
export {};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Errors the memory subsystem shows to people, by code.
|
|
3
|
+
*
|
|
4
|
+
* The engine does not choose a language. The message here is an English
|
|
5
|
+
* default for callers with no strings of their own (logs, the terminal, a
|
|
6
|
+
* model reading a tool error); a frontend with its own strings translates by
|
|
7
|
+
* `code` and `params` instead, as the web page does with `memory.err.*`.
|
|
8
|
+
* Codes are stable. Wording may change.
|
|
9
|
+
*/
|
|
10
|
+
const MESSAGES = {
|
|
11
|
+
configInvalid: "Memory sync settings are invalid, so sync has stopped.",
|
|
12
|
+
stopped: "Memory sync has stopped.",
|
|
13
|
+
disabledHere: "Cloud sync was turned off for these notes.",
|
|
14
|
+
accountChanged: "The signed-in account or Cloud address changed, so memory sync is paused.",
|
|
15
|
+
settingsChanged: "Memory sync settings changed.",
|
|
16
|
+
localUnreadable: "Notes on this machine cannot be read or are invalid. Check the memory folder. Sync is paused and no file was changed.",
|
|
17
|
+
signInFirst: "Sign in to OHarness first.",
|
|
18
|
+
boundElsewhere: "This notes folder is already bound to another account or Cloud. Use a separate notes folder so notes are not uploaded across accounts.",
|
|
19
|
+
verifyFailed: "Account verification failed.",
|
|
20
|
+
syncFailed: "Sync failed.",
|
|
21
|
+
invalidVersion: "The sync service returned an invalid version.",
|
|
22
|
+
waitForSync: "Wait for the current sync to finish.",
|
|
23
|
+
stale: "Notes changed on this machine or another device. Sync, then try again.",
|
|
24
|
+
invalidBatch: "Invalid batch change.",
|
|
25
|
+
batchTooLarge: "Too many notes changed at once. Change them in smaller batches.",
|
|
26
|
+
serverTooOld: "The sync service is too old to sync your own notes. Upgrade the sync service.",
|
|
27
|
+
accountSwitched: "The account changed.",
|
|
28
|
+
invalidChoice: "Invalid conflict choice.",
|
|
29
|
+
localChanged: "Notes on this machine changed. Sync again.",
|
|
30
|
+
oneSideDeleted: "One side deleted this note, so both copies cannot be kept.",
|
|
31
|
+
mergedMissing: "The merged note is missing.",
|
|
32
|
+
secret: "The note seems to contain a credential, so it was not saved.",
|
|
33
|
+
secretFound: "The note seems to contain a credential ({kinds}), so it was not saved.",
|
|
34
|
+
mergedSecret: "The merged note seems to contain a credential, so it was not saved.",
|
|
35
|
+
conflictsPending: "{count} notes were changed on both sides in overlapping ways and could not be merged automatically. Choose which version to keep. Everything else is synced.",
|
|
36
|
+
conflictsRemain: "Some conflicts still need resolving.",
|
|
37
|
+
invalidResponse: "The sync service returned invalid data.",
|
|
38
|
+
signInAgain: "Sign in to OHarness again.",
|
|
39
|
+
requestFailed: "The memory sync request failed or was cancelled. You can try again.",
|
|
40
|
+
cloudChanged: "The cloud version changed. Sync again.",
|
|
41
|
+
rateLimited: "Syncing too often. It will retry automatically.",
|
|
42
|
+
serverNotConfigured: "The sync service has not set up memory sign-in or R2 storage.",
|
|
43
|
+
quotaExceeded: "Over the sync service's memory quota.",
|
|
44
|
+
rejected: "The sync request was refused. Check your account and sync settings.",
|
|
45
|
+
planLimit: "Free cloud sync for memory is full: at most {notes} project notes and {notes} of your own, {kb} KB each. Upgrading removes these limits. Notes on this machine are not affected.",
|
|
46
|
+
planLimitPlain: "Free cloud sync for memory is full. Upgrading removes the limits. Notes on this machine are not affected.",
|
|
47
|
+
responseTooLarge: "The sync response was too large.",
|
|
48
|
+
principalMismatch: "The sync response is for a different account.",
|
|
49
|
+
mergeGone: "The notes to merge no longer exist or have changed.",
|
|
50
|
+
modelNoDraft: "The model did not return a usable merge. You can merge by hand instead.",
|
|
51
|
+
mergeStale: "Notes changed. Suggest the merge again.",
|
|
52
|
+
editStale: "The note changed. Refresh, then edit again.",
|
|
53
|
+
deleteStale: "The note changed. Refresh the page.",
|
|
54
|
+
mergeEmpty: "The merged summary and body cannot be empty.",
|
|
55
|
+
unknownAction: "Unknown memory action.",
|
|
56
|
+
};
|
|
57
|
+
/** Every code and its English message, for frontends that check their strings cover them. */
|
|
58
|
+
export const MEMORY_ERROR_MESSAGES = MESSAGES;
|
|
59
|
+
export class MemoryError extends Error {
|
|
60
|
+
code;
|
|
61
|
+
params;
|
|
62
|
+
constructor(code, params = {}) {
|
|
63
|
+
super(MESSAGES[code].replace(/\{([a-z]+)\}/g, (whole, name) => (params[name] === undefined ? whole : String(params[name]))));
|
|
64
|
+
this.name = "MemoryError";
|
|
65
|
+
this.code = code;
|
|
66
|
+
this.params = params;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export function memoryFailure(error) {
|
|
70
|
+
if (error instanceof MemoryError)
|
|
71
|
+
return { message: error.message, code: error.code, params: error.params };
|
|
72
|
+
return error instanceof Error ? { message: error.message } : { message: MESSAGES.syncFailed, code: "syncFailed" };
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=memory-errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-errors.js","sourceRoot":"","sources":["../../src/agent/memory-errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,QAAQ,GAAG;IACf,aAAa,EAAE,wDAAwD;IACvE,OAAO,EAAE,0BAA0B;IACnC,YAAY,EAAE,4CAA4C;IAC1D,cAAc,EAAE,2EAA2E;IAC3F,eAAe,EAAE,+BAA+B;IAChD,eAAe,EAAE,uHAAuH;IACxI,WAAW,EAAE,4BAA4B;IACzC,cAAc,EAAE,wIAAwI;IACxJ,YAAY,EAAE,8BAA8B;IAC5C,UAAU,EAAE,cAAc;IAC1B,cAAc,EAAE,+CAA+C;IAC/D,WAAW,EAAE,sCAAsC;IACnD,KAAK,EAAE,wEAAwE;IAC/E,YAAY,EAAE,uBAAuB;IACrC,aAAa,EAAE,iEAAiE;IAChF,YAAY,EAAE,+EAA+E;IAC7F,eAAe,EAAE,sBAAsB;IACvC,aAAa,EAAE,0BAA0B;IACzC,YAAY,EAAE,4CAA4C;IAC1D,cAAc,EAAE,4DAA4D;IAC5E,aAAa,EAAE,6BAA6B;IAC5C,MAAM,EAAE,8DAA8D;IACtE,WAAW,EAAE,wEAAwE;IACrF,YAAY,EAAE,qEAAqE;IACnF,gBAAgB,EAAE,8JAA8J;IAChL,eAAe,EAAE,sCAAsC;IACvD,eAAe,EAAE,yCAAyC;IAC1D,WAAW,EAAE,4BAA4B;IACzC,aAAa,EAAE,qEAAqE;IACpF,YAAY,EAAE,wCAAwC;IACtD,WAAW,EAAE,iDAAiD;IAC9D,mBAAmB,EAAE,+DAA+D;IACpF,aAAa,EAAE,uCAAuC;IACtD,QAAQ,EAAE,qEAAqE;IAC/E,SAAS,EAAE,kLAAkL;IAC7L,cAAc,EAAE,2GAA2G;IAC3H,gBAAgB,EAAE,kCAAkC;IACpD,iBAAiB,EAAE,+CAA+C;IAClE,SAAS,EAAE,qDAAqD;IAChE,YAAY,EAAE,yEAAyE;IACvF,UAAU,EAAE,yCAAyC;IACrD,SAAS,EAAE,6CAA6C;IACxD,WAAW,EAAE,qCAAqC;IAClD,UAAU,EAAE,8CAA8C;IAC1D,aAAa,EAAE,wBAAwB;CAC/B,CAAC;AAKX,6FAA6F;AAC7F,MAAM,CAAC,MAAM,qBAAqB,GAA8C,QAAQ,CAAC;AAEzF,MAAM,OAAO,WAAY,SAAQ,KAAK;IAC3B,IAAI,CAAkB;IACtB,MAAM,CAAoB;IACnC,YAAY,IAAqB,EAAE,SAA4B,EAAE;QAC/D,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACrI,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AASD,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,IAAI,KAAK,YAAY,WAAW;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;IAC5G,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;AACpH,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Message } from "../core/types.ts";
|
|
2
|
+
import type { ModelSpec, Provider } from "../providers/types.ts";
|
|
3
|
+
import type { ExtractedNote, ExtractionResult, MemoryCandidate, MemoryExtractionTarget } from "./memory-provider.ts";
|
|
4
|
+
/**
|
|
5
|
+
* Notes proposed by a model reading a finished stretch of conversation.
|
|
6
|
+
*
|
|
7
|
+
* The complement to `remember`, which depends on the agent noticing in the
|
|
8
|
+
* moment. Off by default, because every pass is a model call on the user's
|
|
9
|
+
* own credit. What comes back is treated as untrusted: ids it was not shown
|
|
10
|
+
* are dropped, links it invents are unlinked, credentials are redacted, and
|
|
11
|
+
* everything lands through the same store paths a human edit takes.
|
|
12
|
+
*/
|
|
13
|
+
export declare const EXTRACTION_PROMPT = "You maintain a set of durable notes an assistant reads in future sessions. Read the conversation and propose notes worth keeping.\n\nWorth keeping:\n- a correction the user gave, or an approach they confirmed (type \"feedback\");\n- who the user is or how they like to work (type \"user\");\n- a decision and its reason, a constraint, or ongoing work that the code and git history do not record (type \"project\");\n- where external information lives: a dashboard, a tracker, a document (type \"reference\").\n\nNot worth keeping: anything the code or git history already records, anything only relevant to the task in progress, small talk, credentials or secrets of any kind.\n\nExisting notes come in two lists. Notes shown with their full body may be updated: if a proposal covers the same subject as one of them, use \"action\": \"update\" with its \"id\" and write the complete new body, keeping every detail of the existing body that is still true. Notes listed by summary only may be linked but never updated; propose a new note instead if one of them needs changing.\n\nBodies state the fact, then a line starting \"Why:\" and a line starting \"How to apply:\". Tags carry the words someone might search with instead of the summary's own: synonyms, and the term in the other language the conversation uses. Link related notes as [[id]] using only the ids listed. A new note in this batch can be linked from another new note as [[new:N]], where N is that note's \"ref\".\n\nRespond with a JSON array and nothing else. Each element:\n{\"action\":\"create\"|\"update\",\"id\":\"<existing id, for update>\",\"ref\":<number, for create>,\"summary\":\"<one concrete line>\",\"body\":\"<markdown>\",\"type\":\"user\"|\"feedback\"|\"project\"|\"reference\",\"scope\":\"user\"|\"project\",\"tags\":[\"...\"]}\n\nScope \"project\" is the default, including for feedback about how this codebase is worked on. Use scope \"user\" for facts about the user and for preferences that plainly hold in every project. Return [] when nothing qualifies \u2014 that is the common case.";
|
|
14
|
+
/** The conversation as plain text, newest material kept when it has to be cut. */
|
|
15
|
+
export declare function transcriptText(messages: readonly Message[], maxChars?: number): string;
|
|
16
|
+
/** Real messages from the user: typed, not tool results or harness summaries. */
|
|
17
|
+
export declare function countUserTurns(messages: readonly Message[]): number;
|
|
18
|
+
/**
|
|
19
|
+
* Validate an extractor's reply. Returns only well-formed notes; a reply that
|
|
20
|
+
* is not JSON at all yields none rather than an error, since a model that
|
|
21
|
+
* rambles instead of answering has proposed nothing.
|
|
22
|
+
*/
|
|
23
|
+
export declare function parseExtraction(reply: string, candidates: readonly MemoryCandidate[]): ExtractedNote[];
|
|
24
|
+
/**
|
|
25
|
+
* Replace `[[new:N]]` with the id note N was given. A placeholder whose note
|
|
26
|
+
* was not written becomes plain text.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolvePlaceholders(body: string, ids: ReadonlyMap<number, string>): string;
|
|
29
|
+
export interface ExtractionRun {
|
|
30
|
+
messages: readonly Message[];
|
|
31
|
+
provider: Provider;
|
|
32
|
+
model: ModelSpec;
|
|
33
|
+
target: MemoryExtractionTarget;
|
|
34
|
+
signal?: AbortSignal;
|
|
35
|
+
}
|
|
36
|
+
export declare function extractMemories(run: ExtractionRun): Promise<ExtractionResult>;
|