@duetso/agent 0.2.5 → 0.3.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 +15 -12
- package/dist/package.json +8 -3
- package/dist/src/cli/help.d.ts.map +1 -1
- package/dist/src/cli/help.js +41 -27
- package/dist/src/cli/help.js.map +1 -1
- package/dist/src/cli/memory-add.d.ts +18 -13
- package/dist/src/cli/memory-add.d.ts.map +1 -1
- package/dist/src/cli/memory-add.js +91 -32
- package/dist/src/cli/memory-add.js.map +1 -1
- package/dist/src/cli/memory-recall.d.ts.map +1 -1
- package/dist/src/cli/memory-recall.js +3 -0
- package/dist/src/cli/memory-recall.js.map +1 -1
- package/dist/src/cli/memory-sources.d.ts +20 -0
- package/dist/src/cli/memory-sources.d.ts.map +1 -0
- package/dist/src/cli/memory-sources.js +40 -0
- package/dist/src/cli/memory-sources.js.map +1 -0
- package/dist/src/cli/route.d.ts +2 -0
- package/dist/src/cli/route.d.ts.map +1 -1
- package/dist/src/cli/route.js +8 -8
- package/dist/src/cli/route.js.map +1 -1
- package/dist/src/cli/rpc.d.ts +3 -2
- package/dist/src/cli/rpc.d.ts.map +1 -1
- package/dist/src/cli/rpc.js +3 -2
- package/dist/src/cli/rpc.js.map +1 -1
- package/dist/src/cli/run.d.ts +1 -0
- package/dist/src/cli/run.d.ts.map +1 -1
- package/dist/src/cli/run.js +1 -0
- package/dist/src/cli/run.js.map +1 -1
- package/dist/src/cli/train.d.ts +31 -7
- package/dist/src/cli/train.d.ts.map +1 -1
- package/dist/src/cli/train.js +233 -79
- package/dist/src/cli/train.js.map +1 -1
- package/dist/src/memory/context-pack.d.ts +5 -0
- package/dist/src/memory/context-pack.d.ts.map +1 -1
- package/dist/src/memory/context-pack.js +6 -0
- package/dist/src/memory/context-pack.js.map +1 -1
- package/dist/src/memory/id.d.ts +3 -0
- package/dist/src/memory/id.d.ts.map +1 -0
- package/dist/src/memory/id.js +6 -0
- package/dist/src/memory/id.js.map +1 -0
- package/dist/src/memory/observational-prompts.d.ts +2 -0
- package/dist/src/memory/observational-prompts.d.ts.map +1 -1
- package/dist/src/memory/observational-prompts.js +4 -2
- package/dist/src/memory/observational-prompts.js.map +1 -1
- package/dist/src/memory/observational.d.ts +22 -0
- package/dist/src/memory/observational.d.ts.map +1 -1
- package/dist/src/memory/observational.js +65 -22
- package/dist/src/memory/observational.js.map +1 -1
- package/dist/src/memory/paths.d.ts +9 -0
- package/dist/src/memory/paths.d.ts.map +1 -0
- package/dist/src/memory/paths.js +11 -0
- package/dist/src/memory/paths.js.map +1 -0
- package/dist/src/memory/storage.d.ts.map +1 -1
- package/dist/src/memory/storage.js +1 -4
- package/dist/src/memory/storage.js.map +1 -1
- package/dist/src/memory/store/discovery.d.ts +7 -0
- package/dist/src/memory/store/discovery.d.ts.map +1 -0
- package/dist/src/memory/store/discovery.js +34 -0
- package/dist/src/memory/store/discovery.js.map +1 -0
- package/dist/src/memory/store/file.d.ts +52 -0
- package/dist/src/memory/store/file.d.ts.map +1 -0
- package/dist/src/memory/store/file.js +287 -0
- package/dist/src/memory/store/file.js.map +1 -0
- package/dist/src/memory/store/index.d.ts +5 -0
- package/dist/src/memory/store/index.d.ts.map +1 -0
- package/dist/src/memory/store/index.js +5 -0
- package/dist/src/memory/store/index.js.map +1 -0
- package/dist/src/memory/store/pack.d.ts +25 -0
- package/dist/src/memory/store/pack.d.ts.map +1 -0
- package/dist/src/memory/store/pack.js +71 -0
- package/dist/src/memory/store/pack.js.map +1 -0
- package/dist/src/memory/store/sources.d.ts +55 -0
- package/dist/src/memory/store/sources.d.ts.map +1 -0
- package/dist/src/memory/store/sources.js +85 -0
- package/dist/src/memory/store/sources.js.map +1 -0
- package/dist/src/memory/store/store.d.ts +46 -0
- package/dist/src/memory/store/store.d.ts.map +1 -0
- package/dist/src/memory/store/store.js +171 -0
- package/dist/src/memory/store/store.js.map +1 -0
- package/dist/src/memory/store.d.ts +19 -16
- package/dist/src/memory/store.d.ts.map +1 -1
- package/dist/src/memory/store.js +14 -11
- package/dist/src/memory/store.js.map +1 -1
- package/dist/src/memory-store.js +554 -0
- package/dist/src/model-routing/advisor-context.d.ts +31 -5
- package/dist/src/model-routing/advisor-context.d.ts.map +1 -1
- package/dist/src/model-routing/advisor-context.js +87 -10
- package/dist/src/model-routing/advisor-context.js.map +1 -1
- package/dist/src/model-routing/advisor-lifecycle.d.ts +14 -5
- package/dist/src/model-routing/advisor-lifecycle.d.ts.map +1 -1
- package/dist/src/model-routing/advisor-lifecycle.js +24 -7
- package/dist/src/model-routing/advisor-lifecycle.js.map +1 -1
- package/dist/src/model-routing/prompts.d.ts.map +1 -1
- package/dist/src/model-routing/prompts.js +18 -10
- package/dist/src/model-routing/prompts.js.map +1 -1
- package/dist/src/session/session-manager.d.ts +1 -4
- package/dist/src/session/session-manager.d.ts.map +1 -1
- package/dist/src/session/session-manager.js +2 -5
- package/dist/src/session/session-manager.js.map +1 -1
- package/dist/src/session/session.d.ts +2 -2
- package/dist/src/session/session.js +2 -2
- package/dist/src/train/archive.d.ts.map +1 -1
- package/dist/src/train/archive.js +5 -0
- package/dist/src/train/archive.js.map +1 -1
- package/dist/src/train/types.d.ts +8 -7
- package/dist/src/train/types.d.ts.map +1 -1
- package/dist/src/turn-runner/tools.d.ts +3 -3
- package/dist/src/turn-runner/tools.d.ts.map +1 -1
- package/dist/src/turn-runner/tools.js +1 -1
- package/dist/src/turn-runner/tools.js.map +1 -1
- package/dist/src/turn-runner/turn-runner.d.ts +15 -2
- package/dist/src/turn-runner/turn-runner.d.ts.map +1 -1
- package/dist/src/turn-runner/turn-runner.js +102 -15
- package/dist/src/turn-runner/turn-runner.js.map +1 -1
- package/dist/src/turn-runner/wire-shaping.d.ts +3 -1
- package/dist/src/turn-runner/wire-shaping.d.ts.map +1 -1
- package/dist/src/turn-runner/wire-shaping.js +5 -1
- package/dist/src/turn-runner/wire-shaping.js.map +1 -1
- package/dist/src/types/config.d.ts +7 -0
- package/dist/src/types/config.d.ts.map +1 -1
- package/dist/src/types/protocol.d.ts +2 -2
- package/package.json +8 -3
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import * as fileSystem from "node:fs/promises";
|
|
2
|
+
import { join, resolve } from "node:path";
|
|
3
|
+
import { walkAncestors } from "../../lib/walk-ancestors.js";
|
|
4
|
+
import { DEFAULT_MEMORY_DB_PATH } from "../paths.js";
|
|
5
|
+
import { discoverMemoryStores } from "./discovery.js";
|
|
6
|
+
/**
|
|
7
|
+
* Resolve explicit flags or the skills-style flagless source set.
|
|
8
|
+
*
|
|
9
|
+
* Any explicit backend flag replaces discovery. Without flags, reads inherit
|
|
10
|
+
* every existing memory store from cwd toward the filesystem root and then
|
|
11
|
+
* consult the default DB. Writes target the nearest ancestor that owns an
|
|
12
|
+
* `.agents` directory, falling back to cwd when no agent marker exists; the
|
|
13
|
+
* `memories` child itself is allowed to be absent because writers create it.
|
|
14
|
+
*/
|
|
15
|
+
export async function resolveSources(flags, cwd) {
|
|
16
|
+
const explicitCount = flags.stores.length + flags.dbs.length;
|
|
17
|
+
if (explicitCount > 0) {
|
|
18
|
+
const stores = unique(flags.stores);
|
|
19
|
+
const dbs = unique(flags.dbs);
|
|
20
|
+
const selected = flags.stores[0] ?? flags.dbs[0];
|
|
21
|
+
const writeTarget = explicitCount === 1 && selected
|
|
22
|
+
? { kind: flags.stores.length === 1 ? "store" : "db", path: selected }
|
|
23
|
+
: undefined;
|
|
24
|
+
return {
|
|
25
|
+
stores,
|
|
26
|
+
dbs,
|
|
27
|
+
...(writeTarget ? { writeTarget } : {}),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
const stores = await discoverMemoryStores(cwd);
|
|
31
|
+
return {
|
|
32
|
+
stores,
|
|
33
|
+
dbs: [DEFAULT_MEMORY_DB_PATH],
|
|
34
|
+
writeTarget: { kind: "store", path: await nearestAgentMemoryStore(cwd) },
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Merge projected rows under the one canonical ordering policy.
|
|
39
|
+
*
|
|
40
|
+
* File-store groups precede DB groups; within each family the caller supplies
|
|
41
|
+
* nearest-to-root or explicit flag order. The first row for a slug wins that
|
|
42
|
+
* collision. Only after shadowed copies are removed are all winners sorted
|
|
43
|
+
* newest-first, with the precedence order retained for timestamp ties.
|
|
44
|
+
*/
|
|
45
|
+
export function mergeListings(storeEntries, dbEntries) {
|
|
46
|
+
const winners = new Map();
|
|
47
|
+
for (const listing of storeEntries) {
|
|
48
|
+
for (const entry of listing.entries) {
|
|
49
|
+
if (!winners.has(entry.slug))
|
|
50
|
+
winners.set(entry.slug, { ...entry, store: listing.source });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
for (const listing of dbEntries) {
|
|
54
|
+
for (const entry of listing.entries) {
|
|
55
|
+
if (!winners.has(entry.slug))
|
|
56
|
+
winners.set(entry.slug, { ...entry });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return Array.from(winners.values()).sort((left, right) => right.createdAt - left.createdAt);
|
|
60
|
+
}
|
|
61
|
+
async function nearestAgentMemoryStore(cwd) {
|
|
62
|
+
for (const ancestor of walkAncestors(cwd)) {
|
|
63
|
+
const agentRoot = join(ancestor, ".agents");
|
|
64
|
+
const status = await fileSystem.lstat(agentRoot).catch((error) => {
|
|
65
|
+
if (isNodeError(error, "ENOENT") || isNodeError(error, "ENOTDIR"))
|
|
66
|
+
return undefined;
|
|
67
|
+
throw error;
|
|
68
|
+
});
|
|
69
|
+
if (!status)
|
|
70
|
+
continue;
|
|
71
|
+
if (status.isSymbolicLink())
|
|
72
|
+
throw new Error(`Agent directories cannot be symlinks: ${agentRoot}`);
|
|
73
|
+
if (!status.isDirectory())
|
|
74
|
+
throw new Error(`Agent path is not a directory: ${agentRoot}`);
|
|
75
|
+
return join(agentRoot, "memories");
|
|
76
|
+
}
|
|
77
|
+
return join(resolve(cwd), ".agents", "memories");
|
|
78
|
+
}
|
|
79
|
+
function unique(paths) {
|
|
80
|
+
return Array.from(new Set(paths));
|
|
81
|
+
}
|
|
82
|
+
function isNodeError(error, code) {
|
|
83
|
+
return error instanceof Error && "code" in error && error.code === code;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=sources.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sources.js","sourceRoot":"","sources":["../../../../src/memory/store/sources.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { type MemoryFileRecord } from "./file.js";
|
|
2
|
+
/** Public view of a record read from a concrete memory-store directory. */
|
|
3
|
+
export interface StoredMemory {
|
|
4
|
+
/** Filename stem and authoritative identity within a store. */
|
|
5
|
+
slug: string;
|
|
6
|
+
/** Absolute directory containing the record, used as its provenance layer. */
|
|
7
|
+
storeDir: string;
|
|
8
|
+
/** Stable record identity shared with APIs and private archive metadata. */
|
|
9
|
+
id: string;
|
|
10
|
+
/** Whether the content is synthesized training or a directly curated note. */
|
|
11
|
+
kind: MemoryFileRecord["kind"];
|
|
12
|
+
/** Unix epoch milliseconds used for observed dates and newest-first ordering. */
|
|
13
|
+
createdAt: number;
|
|
14
|
+
/** Short display label for the curated content. */
|
|
15
|
+
headline?: string;
|
|
16
|
+
/** Model identifier that produced synthesized content, when applicable. */
|
|
17
|
+
model?: string;
|
|
18
|
+
/** Number of source files represented by synthesized content. */
|
|
19
|
+
fileCount?: number;
|
|
20
|
+
/** Private archive manifest identifier; never an absolute archive path. */
|
|
21
|
+
archiveId?: string;
|
|
22
|
+
/** Exact curated markdown body. */
|
|
23
|
+
content: string;
|
|
24
|
+
}
|
|
25
|
+
/** Input for a new file; the slug selects its filename and is never serialized. */
|
|
26
|
+
export interface MemoryEntryInput extends MemoryFileRecord {
|
|
27
|
+
/** Safe filename stem used for `<slug>.md`. */
|
|
28
|
+
slug: string;
|
|
29
|
+
}
|
|
30
|
+
/** List valid markdown records in lexical slug order. */
|
|
31
|
+
export declare function listStore(dir: string): Promise<StoredMemory[]>;
|
|
32
|
+
/**
|
|
33
|
+
* List valid records while isolating malformed files. Runtime prompt loading
|
|
34
|
+
* uses this best-effort form so one hand-edited file cannot block startup;
|
|
35
|
+
* management commands retain {@link listStore}'s strict failure behavior.
|
|
36
|
+
*/
|
|
37
|
+
export declare function listStoreTolerant(dir: string, onInvalidEntry: (path: string, error: unknown) => void): Promise<StoredMemory[]>;
|
|
38
|
+
/** Read one record by its safe filename stem. */
|
|
39
|
+
export declare function readEntry(dir: string, slug: string): Promise<StoredMemory>;
|
|
40
|
+
/** Atomically create or replace one memory file. */
|
|
41
|
+
export declare function writeEntry(dir: string, record: MemoryEntryInput): Promise<StoredMemory>;
|
|
42
|
+
/** Replace only a record's curated body while preserving all frontmatter. */
|
|
43
|
+
export declare function updateEntry(dir: string, slug: string, content: string): Promise<StoredMemory>;
|
|
44
|
+
/** Delete one record and return the bytes' parsed public view. */
|
|
45
|
+
export declare function deleteEntry(dir: string, slug: string): Promise<StoredMemory>;
|
|
46
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../../src/memory/store/store.ts"],"names":[],"mappings":"AAKA,OAAO,EAIL,KAAK,gBAAgB,EACtB,MAAM,WAAW,CAAC;AAEnB,2EAA2E;AAC3E,MAAM,WAAW,YAAY;IAC3B,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,8EAA8E;IAC9E,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,EAAE,EAAE,MAAM,CAAC;IACX,8EAA8E;IAC9E,IAAI,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC/B,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC;IAClB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,mFAAmF;AACnF,MAAM,WAAW,gBAAiB,SAAQ,gBAAgB;IACxD,+CAA+C;IAC/C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,yDAAyD;AACzD,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CAEpE;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,EACX,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,GACrD,OAAO,CAAC,YAAY,EAAE,CAAC,CAEzB;AA8BD,iDAAiD;AACjD,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAKhF;AAED,oDAAoD;AACpD,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,YAAY,CAAC,CAuB7F;AAED,6EAA6E;AAC7E,wBAAsB,WAAW,CAC/B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,YAAY,CAAC,CASvB;AAED,kEAAkE;AAClE,wBAAsB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CASlF"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import * as fileSystem from "node:fs/promises";
|
|
4
|
+
import { basename, join, resolve } from "node:path";
|
|
5
|
+
import { parseMemoryFile, serializeMemoryFile, slugFromFilename, } from "./file.js";
|
|
6
|
+
/** List valid markdown records in lexical slug order. */
|
|
7
|
+
export async function listStore(dir) {
|
|
8
|
+
return listStoreWithInvalidPolicy(dir);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* List valid records while isolating malformed files. Runtime prompt loading
|
|
12
|
+
* uses this best-effort form so one hand-edited file cannot block startup;
|
|
13
|
+
* management commands retain {@link listStore}'s strict failure behavior.
|
|
14
|
+
*/
|
|
15
|
+
export async function listStoreTolerant(dir, onInvalidEntry) {
|
|
16
|
+
return listStoreWithInvalidPolicy(dir, onInvalidEntry);
|
|
17
|
+
}
|
|
18
|
+
async function listStoreWithInvalidPolicy(dir, onInvalidEntry) {
|
|
19
|
+
const storeDir = await requireStoreDirectory(dir, false);
|
|
20
|
+
if (!storeDir)
|
|
21
|
+
return [];
|
|
22
|
+
const directoryEntries = await fileSystem.readdir(storeDir, { withFileTypes: true });
|
|
23
|
+
const memoryEntries = directoryEntries
|
|
24
|
+
.filter((entry) => entry.name.endsWith(".md"))
|
|
25
|
+
.sort((left, right) => left.name.localeCompare(right.name));
|
|
26
|
+
const loaded = await Promise.all(memoryEntries.map(async (entry) => {
|
|
27
|
+
const path = join(storeDir, entry.name);
|
|
28
|
+
try {
|
|
29
|
+
if (entry.isSymbolicLink())
|
|
30
|
+
throw new Error(`Memory files cannot be symlinks: ${entry.name}`);
|
|
31
|
+
if (!entry.isFile())
|
|
32
|
+
throw new Error(`Memory entry is not a regular file: ${entry.name}`);
|
|
33
|
+
return await readEntry(storeDir, slugFromFilename(entry.name));
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
if (!onInvalidEntry)
|
|
37
|
+
throw error;
|
|
38
|
+
onInvalidEntry(path, error);
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
}));
|
|
42
|
+
return loaded.filter((entry) => entry !== undefined);
|
|
43
|
+
}
|
|
44
|
+
/** Read one record by its safe filename stem. */
|
|
45
|
+
export async function readEntry(dir, slug) {
|
|
46
|
+
const safeSlug = assertSlug(slug);
|
|
47
|
+
const storeDir = await requireStoreDirectory(dir, false);
|
|
48
|
+
if (!storeDir)
|
|
49
|
+
throw new Error(`Memory store does not exist: ${resolve(dir)}`);
|
|
50
|
+
return (await readParsedEntry(storeDir, safeSlug)).stored;
|
|
51
|
+
}
|
|
52
|
+
/** Atomically create or replace one memory file. */
|
|
53
|
+
export async function writeEntry(dir, record) {
|
|
54
|
+
const slug = assertSlug(record.slug);
|
|
55
|
+
const bytes = serializeMemoryFile(record);
|
|
56
|
+
const storeDir = await requireStoreDirectory(dir, true);
|
|
57
|
+
if (!storeDir)
|
|
58
|
+
throw new Error("Memory store could not be created");
|
|
59
|
+
const destination = join(storeDir, `${slug}.md`);
|
|
60
|
+
await rejectSymlinkIfPresent(destination);
|
|
61
|
+
const temporary = join(storeDir, `.${slug}.${randomUUID()}.tmp`);
|
|
62
|
+
const handle = await fileSystem.open(temporary, "wx", 0o600);
|
|
63
|
+
try {
|
|
64
|
+
try {
|
|
65
|
+
await handle.writeFile(bytes, "utf8");
|
|
66
|
+
await handle.sync();
|
|
67
|
+
}
|
|
68
|
+
finally {
|
|
69
|
+
await handle.close();
|
|
70
|
+
}
|
|
71
|
+
await fileSystem.rename(temporary, destination);
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
await fileSystem.rm(temporary, { force: true });
|
|
75
|
+
throw error;
|
|
76
|
+
}
|
|
77
|
+
return toStoredMemory(storeDir, slug, record);
|
|
78
|
+
}
|
|
79
|
+
/** Replace only a record's curated body while preserving all frontmatter. */
|
|
80
|
+
export async function updateEntry(dir, slug, content) {
|
|
81
|
+
const safeSlug = assertSlug(slug);
|
|
82
|
+
const storeDir = await requireStoreDirectory(dir, false);
|
|
83
|
+
if (!storeDir)
|
|
84
|
+
throw new Error(`Memory store does not exist: ${resolve(dir)}`);
|
|
85
|
+
const { record } = await readParsedEntry(storeDir, safeSlug);
|
|
86
|
+
record.content = content;
|
|
87
|
+
// Keep the parsed object identity so serializeMemoryFile can retain CRLF;
|
|
88
|
+
// spreading here would detach the codec's private line-ending metadata.
|
|
89
|
+
return writeEntry(storeDir, Object.assign(record, { slug: safeSlug }));
|
|
90
|
+
}
|
|
91
|
+
/** Delete one record and return the bytes' parsed public view. */
|
|
92
|
+
export async function deleteEntry(dir, slug) {
|
|
93
|
+
const safeSlug = assertSlug(slug);
|
|
94
|
+
const storeDir = await requireStoreDirectory(dir, false);
|
|
95
|
+
if (!storeDir)
|
|
96
|
+
throw new Error(`Memory store does not exist: ${resolve(dir)}`);
|
|
97
|
+
const { stored } = await readParsedEntry(storeDir, safeSlug);
|
|
98
|
+
const path = join(storeDir, `${safeSlug}.md`);
|
|
99
|
+
await rejectSymlinkIfPresent(path);
|
|
100
|
+
await fileSystem.unlink(path);
|
|
101
|
+
return stored;
|
|
102
|
+
}
|
|
103
|
+
async function readParsedEntry(storeDir, slug) {
|
|
104
|
+
const path = join(storeDir, `${slug}.md`);
|
|
105
|
+
const status = await fileSystem.lstat(path);
|
|
106
|
+
if (status.isSymbolicLink())
|
|
107
|
+
throw new Error(`Memory files cannot be symlinks: ${path}`);
|
|
108
|
+
if (!status.isFile())
|
|
109
|
+
throw new Error(`Memory entry is not a regular file: ${path}`);
|
|
110
|
+
const handle = await fileSystem.open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
111
|
+
const text = await handle.readFile("utf8").finally(() => handle.close());
|
|
112
|
+
const record = parseMemoryFile(text);
|
|
113
|
+
return { stored: toStoredMemory(storeDir, slug, record), record };
|
|
114
|
+
}
|
|
115
|
+
function toStoredMemory(storeDir, slug, record) {
|
|
116
|
+
return {
|
|
117
|
+
slug,
|
|
118
|
+
storeDir,
|
|
119
|
+
id: record.id,
|
|
120
|
+
kind: record.kind,
|
|
121
|
+
createdAt: record.createdAt,
|
|
122
|
+
...(record.headline === undefined ? {} : { headline: record.headline }),
|
|
123
|
+
...(record.model === undefined ? {} : { model: record.model }),
|
|
124
|
+
...(record.fileCount === undefined ? {} : { fileCount: record.fileCount }),
|
|
125
|
+
...(record.archiveId === undefined ? {} : { archiveId: record.archiveId }),
|
|
126
|
+
content: record.content,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function assertSlug(slug) {
|
|
130
|
+
if (basename(slug) !== slug)
|
|
131
|
+
throw new Error(`Unsafe memory slug: ${slug}`);
|
|
132
|
+
return slugFromFilename(`${slug}.md`);
|
|
133
|
+
}
|
|
134
|
+
async function requireStoreDirectory(dir, create) {
|
|
135
|
+
const storeDir = resolve(dir);
|
|
136
|
+
const status = await fileSystem.lstat(storeDir).catch((error) => {
|
|
137
|
+
if (isNodeError(error, "ENOENT"))
|
|
138
|
+
return undefined;
|
|
139
|
+
throw error;
|
|
140
|
+
});
|
|
141
|
+
if (!status && create) {
|
|
142
|
+
await fileSystem.mkdir(storeDir, { recursive: true, mode: 0o700 });
|
|
143
|
+
const createdStatus = await fileSystem.lstat(storeDir);
|
|
144
|
+
if (!createdStatus.isDirectory() || createdStatus.isSymbolicLink()) {
|
|
145
|
+
throw new Error(`Memory store must be a real directory: ${storeDir}`);
|
|
146
|
+
}
|
|
147
|
+
return storeDir;
|
|
148
|
+
}
|
|
149
|
+
if (!status)
|
|
150
|
+
return undefined;
|
|
151
|
+
if (status.isSymbolicLink())
|
|
152
|
+
throw new Error(`Memory stores cannot be symlinks: ${storeDir}`);
|
|
153
|
+
if (!status.isDirectory())
|
|
154
|
+
throw new Error(`Memory store is not a directory: ${storeDir}`);
|
|
155
|
+
return storeDir;
|
|
156
|
+
}
|
|
157
|
+
async function rejectSymlinkIfPresent(path) {
|
|
158
|
+
const status = await fileSystem.lstat(path).catch((error) => {
|
|
159
|
+
if (isNodeError(error, "ENOENT"))
|
|
160
|
+
return undefined;
|
|
161
|
+
throw error;
|
|
162
|
+
});
|
|
163
|
+
if (status?.isSymbolicLink())
|
|
164
|
+
throw new Error(`Memory files cannot be symlinks: ${path}`);
|
|
165
|
+
if (status && !status.isFile())
|
|
166
|
+
throw new Error(`Memory entry is not a regular file: ${path}`);
|
|
167
|
+
}
|
|
168
|
+
function isNodeError(error, code) {
|
|
169
|
+
return error instanceof Error && "code" in error && error.code === code;
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../../src/memory/store/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { Observation } from "../types/memory.js";
|
|
2
|
+
import type { StoredMemory } from "./store/store.js";
|
|
2
3
|
/**
|
|
3
|
-
* Frozen view of memory rendered into the prompt prefix.
|
|
4
|
-
* compaction events
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* point exactly one cache invalidation is paid — not one per turn.
|
|
4
|
+
* Frozen view of memory rendered into the prompt prefix. Database layers are
|
|
5
|
+
* captured at compaction events; curated file memory is captured at initial
|
|
6
|
+
* load and explicit skills reload. Every layer stays immutable between its
|
|
7
|
+
* refresh events so the rendered prefix remains content-deterministic across
|
|
8
|
+
* turns and preserves the provider's prompt cache.
|
|
9
9
|
*
|
|
10
10
|
* Observations the observer writes mid-session still flow to PGlite in
|
|
11
11
|
* real time; they just do not enter `contextPack` until the next
|
|
@@ -13,6 +13,8 @@ import type { Observation } from "../types/memory.js";
|
|
|
13
13
|
* asks.
|
|
14
14
|
*/
|
|
15
15
|
export interface ContextPack {
|
|
16
|
+
/** Curated file memories pinned ahead of every database-backed layer. */
|
|
17
|
+
stored: StoredMemory[];
|
|
16
18
|
/** Cross-session ranked memory; rendered above the local section. */
|
|
17
19
|
global: Observation[];
|
|
18
20
|
/** Current session's chronological compaction summary; rendered below global. */
|
|
@@ -21,23 +23,24 @@ export interface ContextPack {
|
|
|
21
23
|
/**
|
|
22
24
|
* Holds the frozen context pack rendered above the message tail.
|
|
23
25
|
*
|
|
24
|
-
* This is the only
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* the
|
|
29
|
-
* so the provider's prompt cache survives.
|
|
26
|
+
* This is the only memory state the runner keeps in process. Observation
|
|
27
|
+
* rows, ranking, and recall live in PGlite; curated sources live as project
|
|
28
|
+
* files. Holding their rendered view here instead of rereading either source
|
|
29
|
+
* on every dispatch keeps the prefix byte-identical between refresh events so
|
|
30
|
+
* the provider's prompt cache survives.
|
|
30
31
|
*/
|
|
31
32
|
export declare class MemoryContextCache {
|
|
32
33
|
private contextPack;
|
|
33
34
|
/**
|
|
34
|
-
* Replace the
|
|
35
|
+
* Replace the database-backed view used by the runner's context transform.
|
|
35
36
|
* Called by `rebuildMemoryContextPack()` at every compaction trigger
|
|
36
37
|
* (initial load, reflector completion, wire-shaping eviction
|
|
37
|
-
* horizon advance) and never
|
|
38
|
-
*
|
|
38
|
+
* horizon advance) and never for ordinary observation writes. The stored
|
|
39
|
+
* layer is preserved across these database-only refreshes.
|
|
39
40
|
*/
|
|
40
|
-
setContextPack(pack: ContextPack): void;
|
|
41
|
+
setContextPack(pack: Pick<ContextPack, "global" | "local">): void;
|
|
42
|
+
/** Replace only the file-backed layer without disturbing database memory. */
|
|
43
|
+
setStoredContextPack(stored: StoredMemory[]): void;
|
|
41
44
|
/** Current frozen pack. Returns empty arrays when memory is disabled or pre-compaction. */
|
|
42
45
|
getContextPack(): ContextPack;
|
|
43
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/memory/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/memory/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,WAAW;IAC1B,yEAAyE;IACzE,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,qEAAqE;IACrE,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,iFAAiF;IACjF,KAAK,EAAE,WAAW,EAAE,CAAC;CACtB;AAED;;;;;;;;GAQG;AACH,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,WAAW,CAAsD;IAEzE;;;;;;OAMG;IACH,cAAc,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,QAAQ,GAAG,OAAO,CAAC,GAAG,IAAI;IAIjE,6EAA6E;IAC7E,oBAAoB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,IAAI;IAIlD,2FAA2F;IAC3F,cAAc,IAAI,WAAW;CAG9B"}
|
package/dist/src/memory/store.js
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Holds the frozen context pack rendered above the message tail.
|
|
3
3
|
*
|
|
4
|
-
* This is the only
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* the
|
|
9
|
-
* so the provider's prompt cache survives.
|
|
4
|
+
* This is the only memory state the runner keeps in process. Observation
|
|
5
|
+
* rows, ranking, and recall live in PGlite; curated sources live as project
|
|
6
|
+
* files. Holding their rendered view here instead of rereading either source
|
|
7
|
+
* on every dispatch keeps the prefix byte-identical between refresh events so
|
|
8
|
+
* the provider's prompt cache survives.
|
|
10
9
|
*/
|
|
11
10
|
export class MemoryContextCache {
|
|
12
|
-
contextPack = { global: [], local: [] };
|
|
11
|
+
contextPack = { stored: [], global: [], local: [] };
|
|
13
12
|
/**
|
|
14
|
-
* Replace the
|
|
13
|
+
* Replace the database-backed view used by the runner's context transform.
|
|
15
14
|
* Called by `rebuildMemoryContextPack()` at every compaction trigger
|
|
16
15
|
* (initial load, reflector completion, wire-shaping eviction
|
|
17
|
-
* horizon advance) and never
|
|
18
|
-
*
|
|
16
|
+
* horizon advance) and never for ordinary observation writes. The stored
|
|
17
|
+
* layer is preserved across these database-only refreshes.
|
|
19
18
|
*/
|
|
20
19
|
setContextPack(pack) {
|
|
21
|
-
this.contextPack = pack;
|
|
20
|
+
this.contextPack = { ...this.contextPack, ...pack };
|
|
21
|
+
}
|
|
22
|
+
/** Replace only the file-backed layer without disturbing database memory. */
|
|
23
|
+
setStoredContextPack(stored) {
|
|
24
|
+
this.contextPack = { ...this.contextPack, stored };
|
|
22
25
|
}
|
|
23
26
|
/** Current frozen pack. Returns empty arrays when memory is disabled or pre-compaction. */
|
|
24
27
|
getContextPack() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/memory/store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/memory/store.ts"],"names":[],"mappings":"AAwBA;;;;;;;;GAQG;AACH,MAAM,OAAO,kBAAkB;IACrB,WAAW,GAAgB,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAEzE;;;;;;OAMG;IACH,cAAc,CAAC,IAA2C;QACxD,IAAI,CAAC,WAAW,GAAG,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,GAAG,IAAI,EAAE,CAAC;IACtD,CAAC;IAED,6EAA6E;IAC7E,oBAAoB,CAAC,MAAsB;QACzC,IAAI,CAAC,WAAW,GAAG,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,CAAC;IACrD,CAAC;IAED,2FAA2F;IAC3F,cAAc;QACZ,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;CACF"}
|