@agentproto/memory 0.0.0 → 0.1.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 +76 -1
- package/dist/index.d.ts +319 -6
- package/dist/index.mjs +640 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -7,7 +7,8 @@ lifecycle (`active`, then `superseded` or `archived`), stored as markdown
|
|
|
7
7
|
with YAML frontmatter.
|
|
8
8
|
|
|
9
9
|
Spec: <https://agentproto.sh/docs/aip-72>. This package covers the
|
|
10
|
-
document
|
|
10
|
+
document (sections 1 to 7) and the store (section 8); the per-harness
|
|
11
|
+
projection (section 9) lives with the hosts.
|
|
11
12
|
|
|
12
13
|
## Usage
|
|
13
14
|
|
|
@@ -45,6 +46,80 @@ const { ok, errors, warnings } = validateMemory(doc)
|
|
|
45
46
|
active) and an absent `body` as `""`. Lifecycle helpers: `memoryStatus`,
|
|
46
47
|
`isAllowedStatusTransition`, `isInForce`.
|
|
47
48
|
|
|
49
|
+
## Store
|
|
50
|
+
|
|
51
|
+
`MemoryStore` (alias `IMemoryStore`) is the section 8 port: `write`
|
|
52
|
+
(`propose` or `commit`), `read`, `list`, `search`, `supersede`, `archive`,
|
|
53
|
+
`dismiss`. `FilesMemoryStore` implements it over the reference layout:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
<root>/items/<type>/<id>.md one memory/v1 item per file
|
|
57
|
+
<root>/proposals/<sha256>.md pending proposals, not items
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { FilesMemoryStore } from "@agentproto/memory"
|
|
62
|
+
|
|
63
|
+
const store = new FilesMemoryStore({ root: ".agentproto/memory" })
|
|
64
|
+
const rec = await store.write(item, { mode: "commit" }) // assigns an id
|
|
65
|
+
await store.archive(rec.item.id!, { ifRevision: rec.revision })
|
|
66
|
+
const hits = await store.search("pnpm") // in-force items by default
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
- `revision` is the SHA-256 of the file bytes. A commit that changes an
|
|
70
|
+
item, `supersede` and `archive` need the current `ifRevision`, else they
|
|
71
|
+
reject with `MemoryConflictError`; an equal re-write is a no-op.
|
|
72
|
+
- `supersede` and `archive` rewrite the `status` line only; no item file
|
|
73
|
+
is ever deleted. Other failures: `MemoryNotFoundError`,
|
|
74
|
+
`MemoryTransitionError` (e.g. `superseded` to `active`),
|
|
75
|
+
`MemorySlugTakenError`, and `MemoryValidationError` naming the field.
|
|
76
|
+
- `search` matches title, description and body. Pass `knowledge` (any
|
|
77
|
+
AIP-10 `IKnowledgeProvider`, typed structurally so this package does not
|
|
78
|
+
depend on the knowledge engine) to merge its hits: a hit naming an item
|
|
79
|
+
of the store (`metadata.memoryId` or its `sourceId`) is checked against
|
|
80
|
+
the files, anything else comes back as `source: "knowledge"`.
|
|
81
|
+
|
|
82
|
+
## Daemon tools and spawn digest
|
|
83
|
+
|
|
84
|
+
The agentproto daemon (`@agentproto/runtime`) serves a `FilesMemoryStore`
|
|
85
|
+
as MCP tools: `memory_search`, `memory_list`, `memory_read` and
|
|
86
|
+
`memory_write` (default mode `propose`) for every caller, and a `commit`
|
|
87
|
+
mode plus `memory_supersede`, `memory_archive` and `memory_dismiss` for the
|
|
88
|
+
operator or a supervisor session only. Its default root is
|
|
89
|
+
`~/.agentproto/memory` (daemon config `memory.root`). An agent whose
|
|
90
|
+
AGENT.md binds memory (`memory.enabled: true`, `store` or `anchors`) also
|
|
91
|
+
gets the section 9 digest of its in-force, in-scope items appended to its
|
|
92
|
+
system prompt at spawn. See the runtime README's MCP tool surface.
|
|
93
|
+
|
|
94
|
+
## Native memory (claude-code)
|
|
95
|
+
|
|
96
|
+
An adapter declaring `capabilities.memory { inject: "native-dir", capture:
|
|
97
|
+
"native-dir-diff" }` (claude-code) gets the same in-force items written into
|
|
98
|
+
its own memory dir instead of the system prompt:
|
|
99
|
+
|
|
100
|
+
- The dir is `<session config dir>/memory`, pinned through
|
|
101
|
+
`autoMemoryDirectory` in the session's isolated `settings.json`
|
|
102
|
+
(`~/.agentproto/adapter-config/<lineage>/memory`). The user's real
|
|
103
|
+
`~/.claude` is never written.
|
|
104
|
+
- One topic file per item, `agentproto_<slug>.md`, with the native
|
|
105
|
+
frontmatter plus `metadata.agentprotoId`, `agentprotoSlug` and
|
|
106
|
+
`agentprotoSha`. The index lines live in one fenced block at the top of
|
|
107
|
+
`MEMORY.md` (`<!-- agentproto:begin -->` ... `<!-- agentproto:end -->`),
|
|
108
|
+
bounded well under the CLI's 200 lines / 25KB cut and ending with the
|
|
109
|
+
number of items left out. Lines and files the agent wrote are not
|
|
110
|
+
touched; every spawn rewrites only the block and the `agentproto_*` files.
|
|
111
|
+
- Fallback: when auto memory is off (`CLAUDE_CODE_DISABLE_AUTO_MEMORY=1`, a
|
|
112
|
+
repo `.claude/settings*.json` with `autoMemoryEnabled: false`) or the repo
|
|
113
|
+
pins its own `autoMemoryDirectory`, nothing is projected and the digest
|
|
114
|
+
rides the system prompt. Never both.
|
|
115
|
+
- Capture: at each turn end and at exit the daemon diffs the dir against
|
|
116
|
+
the spawn snapshot (`.agentproto-memory.json`) and writes every new or
|
|
117
|
+
changed native file to the agent's store as a proposal (`memory/v1`,
|
|
118
|
+
`provenance.source: native-memory`, `capture.mode: live`). An edited
|
|
119
|
+
projected file is a proposal on the same `id`, a deleted one a proposal
|
|
120
|
+
with `status: archived`. Nothing is committed; a file is proposed once
|
|
121
|
+
per content. Sandbox sessions are not captured yet.
|
|
122
|
+
|
|
48
123
|
## License
|
|
49
124
|
|
|
50
125
|
Apache-2.0. See [LICENSE](./LICENSE).
|
package/dist/index.d.ts
CHANGED
|
@@ -16,10 +16,14 @@ declare const MEMORY_STATUSES: readonly ["active", "superseded", "archived"];
|
|
|
16
16
|
/** Lifecycle status. Absent means `active` (AIP-72 rule 9). */
|
|
17
17
|
type MemoryStatus = (typeof MEMORY_STATUSES)[number];
|
|
18
18
|
interface MemoryAnchor {
|
|
19
|
-
kind: "global" | "project" | "task" | "session" | "pr" | "contact" | "agent";
|
|
19
|
+
kind: "global" | "project" | "task" | "session" | "pr" | "contact" | "agent" | "node" | "operator";
|
|
20
20
|
/** Anchor target slug (project, contact, agent). */
|
|
21
21
|
slug?: string;
|
|
22
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* Anchor target id (task, session, node, operator). A node's is its
|
|
24
|
+
* AIP-34 id (`@<owner>/<slug>`), an operator's the body of its AIP-54
|
|
25
|
+
* `operator:` ref (`<slug>` or `<slug>@<workspace>`). Section 10.
|
|
26
|
+
*/
|
|
23
27
|
id?: string;
|
|
24
28
|
/** Repository `owner/name` for a pr anchor. */
|
|
25
29
|
repo?: string;
|
|
@@ -155,6 +159,14 @@ interface ValidateMemoryOptions {
|
|
|
155
159
|
* section 2 (`kind` set), rules 1, 2, 4 and 5 as errors, rule 8 as
|
|
156
160
|
* warnings. Rules 6 and 7 compare two versions of an item and belong to
|
|
157
161
|
* the store; `isAllowedStatusTransition` covers rule 7's table.
|
|
162
|
+
*
|
|
163
|
+
* Defaults: MEMORY.schema.json gives `tags` (and `evidence.anchorsResolved`,
|
|
164
|
+
* `evidence.flags`) `default: []`, and the generated zod carries it. This
|
|
165
|
+
* function only checks: it never returns the parsed data, so the default
|
|
166
|
+
* is never filled in. An item without `tags` stays without `tags` and
|
|
167
|
+
* reads as untagged (the digest treats it as `global`, AIP-72 section 9).
|
|
168
|
+
* An explicit `tags: []` validates: rule 4 rejects empty strings and empty
|
|
169
|
+
* objects, not empty arrays, though a writer omits it (`defineMemory`).
|
|
158
170
|
*/
|
|
159
171
|
declare function validateMemory(doc: unknown, opts?: ValidateMemoryOptions): MemoryValidationResult;
|
|
160
172
|
|
|
@@ -176,9 +188,13 @@ declare function parseMemory(markdown: string): MemoryDocument;
|
|
|
176
188
|
*
|
|
177
189
|
* Every string value is double-quoted, so a YAML 1.1 or 1.2 reader
|
|
178
190
|
* reads it back as a string (rule 3); undefined fields are omitted
|
|
179
|
-
* (rule 4); key order is the document's own
|
|
180
|
-
*
|
|
181
|
-
*
|
|
191
|
+
* (rule 4); key order is the document's own. So re-rendering a file this
|
|
192
|
+
* function wrote, with only `status` changed, changes only the `status`
|
|
193
|
+
* line (rule 6). That does not hold for a file another writer produced
|
|
194
|
+
* (unquoted strings, other key styles, comments): re-rendering it
|
|
195
|
+
* normalizes every line, which is why the store rewrites the status line
|
|
196
|
+
* in place instead (`setStatusLine`, `files-store.ts`).
|
|
197
|
+
* `parseMemory(renderMemory(d))` deep-equals `d`.
|
|
182
198
|
*/
|
|
183
199
|
declare function renderMemory(doc: MemoryDocument): string;
|
|
184
200
|
|
|
@@ -273,6 +289,8 @@ declare const memoryFrontmatterSchema: z.ZodIntersection<z.ZodObject<{
|
|
|
273
289
|
pr: "pr";
|
|
274
290
|
contact: "contact";
|
|
275
291
|
agent: "agent";
|
|
292
|
+
node: "node";
|
|
293
|
+
operator: "operator";
|
|
276
294
|
}>;
|
|
277
295
|
slug: z.ZodOptional<z.ZodString>;
|
|
278
296
|
id: z.ZodOptional<z.ZodString>;
|
|
@@ -323,6 +341,8 @@ declare const memoryFrontmatterSchema: z.ZodIntersection<z.ZodObject<{
|
|
|
323
341
|
pr: "pr";
|
|
324
342
|
contact: "contact";
|
|
325
343
|
agent: "agent";
|
|
344
|
+
node: "node";
|
|
345
|
+
operator: "operator";
|
|
326
346
|
}>;
|
|
327
347
|
slug: z.ZodOptional<z.ZodString>;
|
|
328
348
|
id: z.ZodOptional<z.ZodString>;
|
|
@@ -345,6 +365,292 @@ declare const memoryFrontmatterSchema: z.ZodIntersection<z.ZodObject<{
|
|
|
345
365
|
body: z.ZodOptional<z.ZodString>;
|
|
346
366
|
}, z.core.$strict>, z.ZodUnion<readonly [z.ZodAny, z.ZodAny]>>;
|
|
347
367
|
|
|
368
|
+
/**
|
|
369
|
+
* AIP-72 section 8: the memory store port.
|
|
370
|
+
*
|
|
371
|
+
* The shapes below are the ones section 8 fixes, name for name. A store
|
|
372
|
+
* keys items by `id`; `slug`, when present, is a second handle that is
|
|
373
|
+
* unique among active items (rule 14). Writes are compare-and-set on the
|
|
374
|
+
* opaque `revision` (rule 17), and nothing is ever hard deleted (rule 16).
|
|
375
|
+
*/
|
|
376
|
+
/** One stored item, or one pending proposal. */
|
|
377
|
+
interface MemoryRecord {
|
|
378
|
+
item: MemoryDocument;
|
|
379
|
+
/** Opaque; changes on every byte change of the stored document. */
|
|
380
|
+
revision: string;
|
|
381
|
+
/** Set on a proposal, absent on an item. */
|
|
382
|
+
proposalId?: string;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* AIP-72 section 10. Built by the host from the calling session, never by
|
|
386
|
+
* the store, and handed in on every operation made on a session's behalf.
|
|
387
|
+
* A call with no `scope` is a host call (rule 30).
|
|
388
|
+
*/
|
|
389
|
+
interface MemoryScope {
|
|
390
|
+
/**
|
|
391
|
+
* The node projection: AIP-34 node ids, nearest first, already cut at a
|
|
392
|
+
* sealed or hard node. Empty: the session has no node scope.
|
|
393
|
+
*/
|
|
394
|
+
readonly nodes: readonly string[];
|
|
395
|
+
/** Id of the root node of the session's tree. */
|
|
396
|
+
readonly tree?: string;
|
|
397
|
+
/** The operator anchor id, when the session runs an operator. */
|
|
398
|
+
readonly operator?: string;
|
|
399
|
+
}
|
|
400
|
+
interface MemoryFilter {
|
|
401
|
+
type?: MemoryType | readonly MemoryType[];
|
|
402
|
+
status?: MemoryStatus | readonly MemoryStatus[];
|
|
403
|
+
/** Matches at most one active item (rule 14, rule 20 overlap). */
|
|
404
|
+
slug?: string;
|
|
405
|
+
/** Match any, e.g. `["global", "project:acme"]`. */
|
|
406
|
+
tags?: readonly string[];
|
|
407
|
+
/** Rules 10 and 11, at the store's clock. */
|
|
408
|
+
inForce?: boolean;
|
|
409
|
+
/** List proposals instead of items. */
|
|
410
|
+
proposals?: boolean;
|
|
411
|
+
/** Section 10: only the items in the scope's node projection. Absent: a host call. */
|
|
412
|
+
scope?: MemoryScope;
|
|
413
|
+
}
|
|
414
|
+
interface MemorySearchHit {
|
|
415
|
+
source: "memory" | "knowledge";
|
|
416
|
+
/** REQUIRED when `source` is `"memory"`. */
|
|
417
|
+
id?: string;
|
|
418
|
+
slug?: string;
|
|
419
|
+
title: string;
|
|
420
|
+
snippet?: string;
|
|
421
|
+
score?: number;
|
|
422
|
+
/** Provider pointer when `source` is `"knowledge"`. */
|
|
423
|
+
ref?: string;
|
|
424
|
+
}
|
|
425
|
+
interface MemoryWriteOptions {
|
|
426
|
+
mode: "propose" | "commit";
|
|
427
|
+
/** The revision the caller last read (rule 17). */
|
|
428
|
+
ifRevision?: string;
|
|
429
|
+
/** The proposal this commit promotes; dropped once the item is written (rule 21). */
|
|
430
|
+
fromProposal?: string;
|
|
431
|
+
/** Section 10: the calling session's scope. Absent: a host call. */
|
|
432
|
+
scope?: MemoryScope;
|
|
433
|
+
/**
|
|
434
|
+
* Rule 32, on a create. `"operator"` (the default) owns the item by the
|
|
435
|
+
* session's operator; `"node"` shares it with every operator of the node.
|
|
436
|
+
*/
|
|
437
|
+
owner?: "operator" | "node";
|
|
438
|
+
}
|
|
439
|
+
interface MemorySearchOptions {
|
|
440
|
+
filter?: MemoryFilter;
|
|
441
|
+
limit?: number;
|
|
442
|
+
}
|
|
443
|
+
interface MemoryStore {
|
|
444
|
+
write(item: MemoryDocument, opts: MemoryWriteOptions): Promise<MemoryRecord>;
|
|
445
|
+
read(id: string, opts?: {
|
|
446
|
+
scope?: MemoryScope;
|
|
447
|
+
}): Promise<MemoryRecord | null>;
|
|
448
|
+
list(filter?: MemoryFilter): Promise<readonly MemoryRecord[]>;
|
|
449
|
+
search(query: string, opts?: MemorySearchOptions): Promise<readonly MemorySearchHit[]>;
|
|
450
|
+
supersede(oldId: string, next: MemoryDocument, opts?: {
|
|
451
|
+
ifRevision?: string;
|
|
452
|
+
scope?: MemoryScope;
|
|
453
|
+
}): Promise<{
|
|
454
|
+
old: MemoryRecord;
|
|
455
|
+
next: MemoryRecord;
|
|
456
|
+
}>;
|
|
457
|
+
archive(id: string, opts?: {
|
|
458
|
+
ifRevision?: string;
|
|
459
|
+
scope?: MemoryScope;
|
|
460
|
+
}): Promise<MemoryRecord>;
|
|
461
|
+
dismiss(proposalId: string, opts?: {
|
|
462
|
+
scope?: MemoryScope;
|
|
463
|
+
}): Promise<void>;
|
|
464
|
+
}
|
|
465
|
+
/** The section 8 port under the `I*` name its knowledge sibling uses. */
|
|
466
|
+
type IMemoryStore = MemoryStore;
|
|
467
|
+
type MemoryStoreErrorCode = "conflict" | "not-found" | "invalid-transition" | "slug-taken";
|
|
468
|
+
/**
|
|
469
|
+
* Base of the store's typed failures. An invalid document is rejected
|
|
470
|
+
* with the document package's `MemoryValidationError` instead, which
|
|
471
|
+
* names the field (rule 13).
|
|
472
|
+
*/
|
|
473
|
+
declare class MemoryStoreError extends Error {
|
|
474
|
+
readonly code: MemoryStoreErrorCode;
|
|
475
|
+
constructor(code: MemoryStoreErrorCode, message: string);
|
|
476
|
+
}
|
|
477
|
+
/** Rule 17: `ifRevision` missing or stale on a write that needs it. */
|
|
478
|
+
declare class MemoryConflictError extends MemoryStoreError {
|
|
479
|
+
readonly id: string;
|
|
480
|
+
/** The revision the caller sent, if any. */
|
|
481
|
+
readonly expected: string | undefined;
|
|
482
|
+
/** The revision on disk, `undefined` when the item does not exist. */
|
|
483
|
+
readonly actual: string | undefined;
|
|
484
|
+
constructor(id: string, expected: string | undefined, actual: string | undefined);
|
|
485
|
+
}
|
|
486
|
+
/** No item (or proposal) with that id. */
|
|
487
|
+
declare class MemoryNotFoundError extends MemoryStoreError {
|
|
488
|
+
readonly id: string;
|
|
489
|
+
readonly what: "item" | "proposal";
|
|
490
|
+
constructor(what: "item" | "proposal", id: string);
|
|
491
|
+
}
|
|
492
|
+
/** Rules 7 and 15: a status move the store does not allow. */
|
|
493
|
+
declare class MemoryTransitionError extends MemoryStoreError {
|
|
494
|
+
readonly id: string;
|
|
495
|
+
readonly from: MemoryStatus;
|
|
496
|
+
readonly to: MemoryStatus;
|
|
497
|
+
constructor(id: string, from: MemoryStatus, to: MemoryStatus, detail?: string);
|
|
498
|
+
}
|
|
499
|
+
/** Rule 14: another active item already holds the slug. */
|
|
500
|
+
declare class MemorySlugTakenError extends MemoryStoreError {
|
|
501
|
+
readonly slug: string;
|
|
502
|
+
/** The active item holding it. */
|
|
503
|
+
readonly holder: string;
|
|
504
|
+
constructor(slug: string, holder: string);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
type Tagged = Pick<MemoryFrontmatter, "tags">;
|
|
508
|
+
/** `node:<id>`, `id` being the AIP-34 id of a node (`@<owner>/<slug>`). */
|
|
509
|
+
declare function nodeTag(id: string): string;
|
|
510
|
+
/** `operator:<id>`, `id` being the body of an AIP-54 `operator:` ref. */
|
|
511
|
+
declare function operatorTag(id: string): string;
|
|
512
|
+
/** The ids of the item's node anchors (an item carries at most one). */
|
|
513
|
+
declare function nodeAnchorIds(item: Tagged): string[];
|
|
514
|
+
/** The ids of the item's operator anchors (an item carries at most one). */
|
|
515
|
+
declare function operatorAnchorIds(item: Tagged): string[];
|
|
516
|
+
/** Whether a tag is a node or operator anchor (neither counts as an anchor for section 9). */
|
|
517
|
+
declare function isNodeOrOperatorTag(tag: string): boolean;
|
|
518
|
+
interface NodeProjectionOptions {
|
|
519
|
+
/**
|
|
520
|
+
* Operator anchor ids the store's AIP-38 read grants let the session
|
|
521
|
+
* read (condition 4). A grant never extends condition 2.
|
|
522
|
+
*/
|
|
523
|
+
grantedOperators?: Iterable<string>;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* Conditions 2 and 4 of the node projection (section 10), the two that
|
|
527
|
+
* read an item's node and operator anchors. Conditions 1 (in force) and 3
|
|
528
|
+
* (the session's flat anchors) stay with the caller, which has the clock
|
|
529
|
+
* and the anchors; the conditions are an intersection.
|
|
530
|
+
*
|
|
531
|
+
* - With a node scope the item must carry a node anchor, and every node
|
|
532
|
+
* anchor it carries must be in `scope.nodes`; an item with none is out.
|
|
533
|
+
* - Without one, an item with a node anchor is out and one with none is
|
|
534
|
+
* judged by the other conditions alone.
|
|
535
|
+
* - An operator anchor needs the session to run that operator, or a grant.
|
|
536
|
+
*/
|
|
537
|
+
declare function isInNodeProjection(item: Tagged, scope: MemoryScope, opts?: NodeProjectionOptions): boolean;
|
|
538
|
+
interface WriteScopeOptions {
|
|
539
|
+
/** Rule 32. Default `"operator"`; `"node"` adds no operator anchor. */
|
|
540
|
+
owner?: "operator" | "node";
|
|
541
|
+
/**
|
|
542
|
+
* The item this write replaces or supersedes. A document that names no
|
|
543
|
+
* node anchor keeps the basis's, and a document that names no owner keeps
|
|
544
|
+
* the basis's kind of ownership, so an edit never moves or hands over an
|
|
545
|
+
* item by default (rule 34: nothing promotes an item by itself).
|
|
546
|
+
*/
|
|
547
|
+
basis?: Tagged;
|
|
548
|
+
/** Rule 33: the host declares trees, so a document with no node anchor is refused. */
|
|
549
|
+
declaresTrees?: boolean;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* The document a write stores: the node and operator anchors added by
|
|
553
|
+
* default (rules 31 to 33), or a validation error naming `tags`. `scope`
|
|
554
|
+
* absent is a host call (rule 30): nothing is added or confined, but a
|
|
555
|
+
* store whose host declares trees still refuses a document with no node
|
|
556
|
+
* anchor (rule 33).
|
|
557
|
+
*/
|
|
558
|
+
declare function applyWriteScope(item: MemoryDocument, scope: MemoryScope | undefined, opts?: WriteScopeOptions): MemoryDocument;
|
|
559
|
+
/**
|
|
560
|
+
* Rule 34. A commit that moves an item to another node changes that anchor
|
|
561
|
+
* and nothing else: not the operator anchor, not the other anchors. (That
|
|
562
|
+
* the new node is in `scope.nodes` is `applyWriteScope`'s check; a node above
|
|
563
|
+
* a sealed or hard wall never is, the projection being cut there.)
|
|
564
|
+
*/
|
|
565
|
+
declare function assertRetagOnly(before: Tagged, after: Tagged): void;
|
|
566
|
+
|
|
567
|
+
/**
|
|
568
|
+
* One hit of a knowledge provider, as much of the AIP-10
|
|
569
|
+
* `KnowledgeHit` as the store reads.
|
|
570
|
+
*/
|
|
571
|
+
interface MemoryKnowledgeHit {
|
|
572
|
+
readonly sourceId: string;
|
|
573
|
+
readonly chunkId?: string;
|
|
574
|
+
readonly text: string;
|
|
575
|
+
readonly score: number;
|
|
576
|
+
/** `memoryId` (string) names the memory item the hit was indexed from. */
|
|
577
|
+
readonly metadata?: Readonly<Record<string, unknown>>;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* The slice of an AIP-10 `IKnowledgeProvider` (`@agentproto/knowledge-engine`)
|
|
581
|
+
* the store delegates search to. Declared structurally so this package
|
|
582
|
+
* takes no dependency on the knowledge engine: any `IKnowledgeProvider`
|
|
583
|
+
* fits as is.
|
|
584
|
+
*/
|
|
585
|
+
interface MemoryKnowledgeProvider {
|
|
586
|
+
query(q: {
|
|
587
|
+
readonly query: string;
|
|
588
|
+
readonly topK?: number;
|
|
589
|
+
}): Promise<{
|
|
590
|
+
readonly hits: readonly MemoryKnowledgeHit[];
|
|
591
|
+
}>;
|
|
592
|
+
}
|
|
593
|
+
interface FilesMemoryStoreOptions {
|
|
594
|
+
/** The store directory: `items/<type>/<id>.md` and `proposals/<id>.md` below it. */
|
|
595
|
+
root: string;
|
|
596
|
+
/**
|
|
597
|
+
* Optional search delegate. Its hits are merged with the built-in
|
|
598
|
+
* keyword match: a hit naming an item of this store is checked against
|
|
599
|
+
* the files (rule 22), anything else comes back as `source: "knowledge"`.
|
|
600
|
+
*/
|
|
601
|
+
knowledge?: MemoryKnowledgeProvider;
|
|
602
|
+
/** The store's clock: `updated_at` on commits, and the in-force check. */
|
|
603
|
+
now?: () => Date;
|
|
604
|
+
/**
|
|
605
|
+
* The host declares AIP-34 trees (section 10, rule 33): a host call that
|
|
606
|
+
* creates an item or a proposal with no node anchor is refused. Off: the
|
|
607
|
+
* store behaves as sections 8 and 9 alone.
|
|
608
|
+
*/
|
|
609
|
+
declaresTrees?: boolean;
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* AIP-72 section 8 reference store over a directory:
|
|
613
|
+
*
|
|
614
|
+
* ```
|
|
615
|
+
* <root>/items/<type>/<id>.md one memory/v1 item per file
|
|
616
|
+
* <root>/proposals/<sha256>.md pending proposals, not items
|
|
617
|
+
* ```
|
|
618
|
+
*
|
|
619
|
+
* The files are the source of truth and the store keeps no index.
|
|
620
|
+
* `revision` is the SHA-256 (hex) of the file bytes, a proposal id the
|
|
621
|
+
* SHA-256 of the rendered proposal. Files are written to a temp file
|
|
622
|
+
* then renamed into place. Item files are never deleted: a type change
|
|
623
|
+
* renames the file, supersede and archive rewrite the `status` line
|
|
624
|
+
* only. Mutations through one instance are serialized, so a
|
|
625
|
+
* compare-and-set cannot interleave with another write of the same
|
|
626
|
+
* store object; several processes writing one directory are not
|
|
627
|
+
* coordinated.
|
|
628
|
+
*/
|
|
629
|
+
declare class FilesMemoryStore implements MemoryStore {
|
|
630
|
+
#private;
|
|
631
|
+
constructor(options: FilesMemoryStoreOptions);
|
|
632
|
+
write(item: MemoryDocument, opts: MemoryWriteOptions): Promise<MemoryRecord>;
|
|
633
|
+
read(id: string, opts?: {
|
|
634
|
+
scope?: MemoryScope;
|
|
635
|
+
}): Promise<MemoryRecord | null>;
|
|
636
|
+
list(filter?: MemoryFilter): Promise<readonly MemoryRecord[]>;
|
|
637
|
+
search(query: string, opts?: MemorySearchOptions): Promise<readonly MemorySearchHit[]>;
|
|
638
|
+
supersede(oldId: string, next: MemoryDocument, opts?: {
|
|
639
|
+
ifRevision?: string;
|
|
640
|
+
scope?: MemoryScope;
|
|
641
|
+
}): Promise<{
|
|
642
|
+
old: MemoryRecord;
|
|
643
|
+
next: MemoryRecord;
|
|
644
|
+
}>;
|
|
645
|
+
archive(id: string, opts?: {
|
|
646
|
+
ifRevision?: string;
|
|
647
|
+
scope?: MemoryScope;
|
|
648
|
+
}): Promise<MemoryRecord>;
|
|
649
|
+
dismiss(proposalId: string, opts?: {
|
|
650
|
+
scope?: MemoryScope;
|
|
651
|
+
}): Promise<void>;
|
|
652
|
+
}
|
|
653
|
+
|
|
348
654
|
/**
|
|
349
655
|
* @agentproto/memory: AIP-72 memory/v1 reference implementation.
|
|
350
656
|
*
|
|
@@ -358,8 +664,15 @@ declare const memoryFrontmatterSchema: z.ZodIntersection<z.ZodObject<{
|
|
|
358
664
|
* - TS: `defineMemory({...})` -> frozen `MemoryHandle` (writer, canonical)
|
|
359
665
|
* - MD: `parseMemory(src)` -> `MemoryDocument`, then `validateMemory(doc)`
|
|
360
666
|
* - out: `renderMemory(doc)` -> MEMORY.md text
|
|
667
|
+
*
|
|
668
|
+
* Store (section 8): the `MemoryStore` port and `FilesMemoryStore`, the
|
|
669
|
+
* reference layout (`items/<type>/<id>.md`, `proposals/<id>.md`).
|
|
670
|
+
*
|
|
671
|
+
* Node scope (section 10): `MemoryScope`, the `node:` and `operator:`
|
|
672
|
+
* anchors, and the projection and write rules over a scope the host
|
|
673
|
+
* computed (`isInNodeProjection`, `applyWriteScope`).
|
|
361
674
|
*/
|
|
362
675
|
declare const SPEC_NAME: "memory/v1";
|
|
363
676
|
declare const SPEC_VERSION: "1.0.0-alpha";
|
|
364
677
|
|
|
365
|
-
export { MEMORY_STATUSES, MEMORY_TYPES, type MemoryAnchor, type MemoryCapture, type MemoryDecidedBy, type MemoryDefinition, type MemoryDocument, type MemoryEvidence, type MemoryFrontmatter, type MemoryHandle, type MemoryIssue, type MemoryLifetime, MemoryParseError, type MemoryProvenance, type MemoryStatus, type MemoryType, MemoryValidationError, type MemoryValidationResult, SPEC_NAME, SPEC_VERSION, type ValidateMemoryOptions, defineMemory, isAllowedStatusTransition, isInForce, memoryFrontmatterSchema, memoryStatus, parseMemory, renderMemory, validateMemory };
|
|
678
|
+
export { FilesMemoryStore, type FilesMemoryStoreOptions, type IMemoryStore, MEMORY_STATUSES, MEMORY_TYPES, type MemoryAnchor, type MemoryCapture, MemoryConflictError, type MemoryDecidedBy, type MemoryDefinition, type MemoryDocument, type MemoryEvidence, type MemoryFilter, type MemoryFrontmatter, type MemoryHandle, type MemoryIssue, type MemoryKnowledgeHit, type MemoryKnowledgeProvider, type MemoryLifetime, MemoryNotFoundError, MemoryParseError, type MemoryProvenance, type MemoryRecord, type MemoryScope, type MemorySearchHit, type MemorySearchOptions, MemorySlugTakenError, type MemoryStatus, type MemoryStore, MemoryStoreError, type MemoryStoreErrorCode, MemoryTransitionError, type MemoryType, MemoryValidationError, type MemoryValidationResult, type MemoryWriteOptions, type NodeProjectionOptions, SPEC_NAME, SPEC_VERSION, type ValidateMemoryOptions, type WriteScopeOptions, applyWriteScope, assertRetagOnly, defineMemory, isAllowedStatusTransition, isInForce, isInNodeProjection, isNodeOrOperatorTag, memoryFrontmatterSchema, memoryStatus, nodeAnchorIds, nodeTag, operatorAnchorIds, operatorTag, parseMemory, renderMemory, validateMemory };
|