@kindgi/memory 0.1.4 → 0.1.5

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/errors.d.ts CHANGED
@@ -10,7 +10,7 @@ import type { FactId, LogEntryId } from '@kindgi/types';
10
10
  * rejection modes (no-embedding-provider, unknown-embedding-model,
11
11
  * ambiguous-default-provider).
12
12
  */
13
- export type MemoryError = InvalidLogEntryError | InvalidFactError | FactNotFoundError | LogNotFoundError | EmbeddingError | RefreshHandlerMissingError | RetentionViolationError | PersistenceError;
13
+ export type MemoryError = InvalidLogEntryError | InvalidFactError | FactNotFoundError | LogNotFoundError | EmbeddingError | RefreshHandlerMissingError | RetentionViolationError | ErasureInProgressError | PersistenceError;
14
14
  export interface InvalidLogEntryError {
15
15
  readonly code: 'invalid-log-entry';
16
16
  readonly message: string;
@@ -50,6 +50,15 @@ export interface RetentionViolationError {
50
50
  readonly factId: FactId;
51
51
  readonly reason: 'legal-hold' | 'keep-until' | 'keep-days';
52
52
  }
53
+ /**
54
+ * A write for a person (by scope or subject), or a conversation, that an
55
+ * erasure in progress holds: nothing new lands for them until it
56
+ * completes.
57
+ */
58
+ export interface ErasureInProgressError {
59
+ readonly code: 'erasure-in-progress';
60
+ readonly message: string;
61
+ }
53
62
  export interface PersistenceError {
54
63
  readonly code: 'persistence-error';
55
64
  readonly message: string;
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAExD;;;;;;;;;GASG;AACH,MAAM,MAAM,WAAW,GACnB,oBAAoB,GACpB,gBAAgB,GAChB,iBAAiB,GACjB,gBAAgB,GAChB,cAAc,GACd,0BAA0B,GAC1B,uBAAuB,GACvB,gBAAgB,CAAC;AAErB,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CACjC;AAED;;;GAGG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,IAAI,EAAE,yBAAyB,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,GAAG,WAAW,CAAC;CAC5D;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAExD;;;;;;;;;GASG;AACH,MAAM,MAAM,WAAW,GACnB,oBAAoB,GACpB,gBAAgB,GAChB,iBAAiB,GACjB,gBAAgB,GAChB,cAAc,GACd,0BAA0B,GAC1B,uBAAuB,GACvB,sBAAsB,GACtB,gBAAgB,CAAC;AAErB,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC;CACjC;AAED;;;GAGG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,IAAI,EAAE,yBAAyB,CAAC;IACzC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;GAGG;AACH,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,GAAG,WAAW,CAAC;CAC5D;AAED;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,mBAAmB,CAAC;IACnC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB"}
@@ -0,0 +1,20 @@
1
+ /** The `k` of reciprocal rank fusion: how much the top ranks dominate (60 is the usual choice). */
2
+ export declare const RRF_K = 60;
3
+ /** One fused item: its score and its 1-based rank in each leg that found it. */
4
+ export interface Fused<T> {
5
+ readonly item: T;
6
+ /** `Σ 1 / (k + rank)` over the legs that found it. */
7
+ readonly score: number;
8
+ /** Its rank in each leg, by the leg's name; absent where that leg didn't find it. */
9
+ readonly ranks: Readonly<Record<string, number>>;
10
+ }
11
+ /**
12
+ * Reciprocal rank fusion of ranked result lists ("legs", each best
13
+ * first): every item scores `Σ 1 / (k + rank)` over the legs that found
14
+ * it, so agreement between legs wins and raw scores (a full-text rank, a
15
+ * cosine similarity) never need to be compared. Ties keep the order of
16
+ * the first leg that found them. Items are matched across legs by `key`;
17
+ * the first leg's copy of an item is kept.
18
+ */
19
+ export declare function fuseByRank<T>(legs: Readonly<Record<string, readonly T[]>>, key: (item: T) => string, k?: number): readonly Fused<T>[];
20
+ //# sourceMappingURL=fusion.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fusion.d.ts","sourceRoot":"","sources":["../src/fusion.ts"],"names":[],"mappings":"AAGA,mGAAmG;AACnG,eAAO,MAAM,KAAK,KAAK,CAAC;AAExB,gFAAgF;AAChF,MAAM,WAAW,KAAK,CAAC,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACjB,sDAAsD;IACtD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,qFAAqF;IACrF,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAClD;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAC1B,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC,EAC5C,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,EACxB,CAAC,GAAE,MAAc,GAChB,SAAS,KAAK,CAAC,CAAC,CAAC,EAAE,CAsBrB"}
package/dist/fusion.js ADDED
@@ -0,0 +1,34 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ /** The `k` of reciprocal rank fusion: how much the top ranks dominate (60 is the usual choice). */
4
+ export const RRF_K = 60;
5
+ /**
6
+ * Reciprocal rank fusion of ranked result lists ("legs", each best
7
+ * first): every item scores `Σ 1 / (k + rank)` over the legs that found
8
+ * it, so agreement between legs wins and raw scores (a full-text rank, a
9
+ * cosine similarity) never need to be compared. Ties keep the order of
10
+ * the first leg that found them. Items are matched across legs by `key`;
11
+ * the first leg's copy of an item is kept.
12
+ */
13
+ export function fuseByRank(legs, key, k = RRF_K) {
14
+ const fused = new Map();
15
+ let seen = 0;
16
+ for (const [leg, items] of Object.entries(legs)) {
17
+ items.forEach((item, i) => {
18
+ const id = key(item);
19
+ const rank = i + 1;
20
+ const entry = fused.get(id);
21
+ if (entry === undefined) {
22
+ fused.set(id, { item, score: 1 / (k + rank), ranks: { [leg]: rank }, first: seen++ });
23
+ }
24
+ else if (entry.ranks[leg] === undefined) {
25
+ entry.score += 1 / (k + rank);
26
+ entry.ranks[leg] = rank;
27
+ }
28
+ });
29
+ }
30
+ return [...fused.values()]
31
+ .sort((a, b) => b.score - a.score || a.first - b.first)
32
+ .map(({ item, score, ranks }) => ({ item, score, ranks }));
33
+ }
34
+ //# sourceMappingURL=fusion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fusion.js","sourceRoot":"","sources":["../src/fusion.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC;AAEjC,mGAAmG;AACnG,MAAM,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;AAWxB;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CACxB,IAA4C,EAC5C,GAAwB,EACxB,IAAY,KAAK;IAEjB,MAAM,KAAK,GAAG,IAAI,GAAG,EAGlB,CAAC;IACJ,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAChD,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;YACxB,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;YACrB,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;YACnB,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC5B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;YACxF,CAAC;iBAAM,IAAI,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;gBAC1C,KAAK,CAAC,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;gBAC9B,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;YAC1B,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;SACvB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;SACtD,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAC/D,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,7 +1,13 @@
1
- export type { Fact, MemoryScope, Retention, Source, SourceFreshness, SourceRefresh, } from './types.js';
1
+ export type { Fact, FactAttribution, FactGeneratedBy, FactInvalidationReason, FactSubject, FactTrust, MemoryReaders, MemoryScope, Retention, Source, SourceFreshness, SourceRefresh, } from './types.js';
2
+ export { isReadableBy } from './readers.js';
3
+ export { isRecallReadableBy } from './recall.js';
4
+ export type { RecallHit, RecallRow, RecallSelection, RecalledMessage, SearchConversationsInput, } from './recall.js';
5
+ export { RRF_K, fuseByRank } from './fusion.js';
6
+ export type { Fused } from './fusion.js';
2
7
  export { LOG_KINDS } from './log.js';
3
8
  export type { LogEntry, LogKind } from './log.js';
4
9
  export type { RetrievalHit } from './retrieval.js';
5
- export type { FactNotFoundError, InvalidFactError, InvalidLogEntryError, LogNotFoundError, MemoryError, PersistenceError, RefreshHandlerMissingError, RetentionViolationError, } from './errors.js';
10
+ export type { ErasureInProgressError, FactNotFoundError, InvalidFactError, InvalidLogEntryError, LogNotFoundError, MemoryError, PersistenceError, RefreshHandlerMissingError, RetentionViolationError, } from './errors.js';
11
+ export type { MemoryRememberBinding, RememberFactInput, RememberFactResult, RememberReviewReason, RememberedContent, } from './remember.js';
6
12
  export type { AppendLogInput, ListFactsInput, MemoryQueryBinding, ReadLogInput, SearchByKeywordInput, SearchBySemanticInput, } from './memory-binding.js';
7
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,YAAY,EACV,IAAI,EACJ,WAAW,EACX,SAAS,EACT,MAAM,EACN,eAAe,EACf,aAAa,GACd,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAGlD,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGnD,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,YAAY,EACV,IAAI,EACJ,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,WAAW,EACX,SAAS,EACT,aAAa,EACb,WAAW,EACX,SAAS,EACT,MAAM,EACN,eAAe,EACf,aAAa,GACd,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAG5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,YAAY,EACV,SAAS,EACT,SAAS,EACT,eAAe,EACf,eAAe,EACf,wBAAwB,GACzB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAChD,YAAY,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAGzC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAGlD,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGnD,YAAY,EACV,sBAAsB,EACtB,iBAAiB,EACjB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,aAAa,CAAC;AAGrB,YAAY,EACV,qBAAqB,EACrB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAGvB,YAAY,EACV,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,YAAY,EACZ,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -1,5 +1,11 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // Copyright (C) 2026 Kindgi Inc.
3
+ // ============ The scope guard ============
4
+ export { isReadableBy } from './readers.js';
5
+ // ============ Recalling earlier conversations ============
6
+ export { isRecallReadableBy } from './recall.js';
7
+ // ============ Hybrid retrieval ============
8
+ export { RRF_K, fuseByRank } from './fusion.js';
3
9
  // ============ Log types ============
4
10
  export { LOG_KINDS } from './log.js';
5
11
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC;AAYjC,sCAAsC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC;AAkBjC,4CAA4C;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,4DAA4D;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AASjD,6CAA6C;AAC7C,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGhD,sCAAsC;AACtC,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC"}
package/dist/log.d.ts CHANGED
@@ -27,5 +27,19 @@ export interface LogEntry {
27
27
  readonly prevHash: string;
28
28
  readonly entryHash: string;
29
29
  readonly causedByLogId?: string;
30
+ /**
31
+ * How `entryHash` was computed. `2`: over the payload's hash
32
+ * (`contentHash`), so a payload cleared by an erasure still verifies.
33
+ * `1` (entries from before): over the payload itself. Absent: 1.
34
+ */
35
+ readonly hashVersion?: 1 | 2;
36
+ /** When an erasure cleared `payload` (its `contentHash` stays). */
37
+ readonly payloadErasedAt?: Timestamp;
38
+ /**
39
+ * The salt of a v2 entry's `contentHash`: the hash is over the payload
40
+ * and this salt, so it can't confirm a guessed payload. An erasure
41
+ * clears it with the payload.
42
+ */
43
+ readonly payloadSalt?: string;
30
44
  }
31
45
  //# sourceMappingURL=log.d.ts.map
package/dist/log.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAElE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,8FAA8F;AAC9F,eAAO,MAAM,SAAS,4OAcZ,CAAC;AAEX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjD;;;;;;;;GAQG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,qDAAqD;IACrD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,gCAAgC;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC"}
1
+ {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAElE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,8FAA8F;AAC9F,eAAO,MAAM,SAAS,4OAcZ,CAAC;AAEX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;AAEjD;;;;;;;;GAQG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,EAAE,UAAU,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;IACtB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,qDAAqD;IACrD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,gCAAgC;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;IAC7B,mEAAmE;IACnE,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B"}
@@ -1,6 +1,7 @@
1
1
  import type { EmbeddingProviderRegistry } from '@kindgi/embedding';
2
- import type { Fact, LogEntry, LogKind, MemoryError, MemoryScope, RetrievalHit } from '@kindgi/memory';
2
+ import type { Fact, LogEntry, LogKind, MemoryError, MemoryReaders, MemoryScope, RetrievalHit } from '@kindgi/memory';
3
3
  import type { Result, RunId, TenantId } from '@kindgi/types';
4
+ import type { RecallHit, SearchConversationsInput } from './recall.js';
4
5
  /**
5
6
  * Caller-plugged data-access surface for the memory subsystem. Agent
6
7
  * code routes its memory reads through this binding — @kindgi/agents
@@ -21,7 +22,9 @@ import type { Result, RunId, TenantId } from '@kindgi/types';
21
22
  export interface MemoryQueryBinding {
22
23
  /**
23
24
  * List facts filtered by tenant, type, and scope, capped by `limit`
24
- * (no pagination cursor). Default: latest version per `(type, id)`.
25
+ * (no pagination cursor): each fact's current revision, never one
26
+ * pending review, and only what `readers` may see (the guard, applied
27
+ * in the query before the limit).
25
28
  */
26
29
  listFacts<TContent = unknown>(input: ListFactsInput): Promise<Result<readonly Fact<TContent>[], MemoryError>>;
27
30
  /**
@@ -36,6 +39,18 @@ export interface MemoryQueryBinding {
36
39
  * embeds the query; the impl runs the vector search.
37
40
  */
38
41
  searchBySemantic<TContent = unknown>(input: SearchBySemanticInput): Promise<Result<readonly RetrievalHit<TContent>[], MemoryError>>;
42
+ /**
43
+ * Recall messages of earlier conversations (a retrieval intent with
44
+ * `source: 'conversations'`): what `readers` may recall
45
+ * (`isRecallReadableBy`), narrowed by `selections`, newest first
46
+ * (`list`), by full-text rank (`keyword`) or by meaning (`semantic`).
47
+ * Never a comparison's replay conversation (an eval run's replay turn
48
+ * opens one): its messages are no one's earlier conversation.
49
+ * Optional: without it, such an intent recalls nothing and its turn
50
+ * journals why. `semantic` without embeddings answers
51
+ * `embedding-unavailable`, as fact search does.
52
+ */
53
+ searchConversations?(input: SearchConversationsInput): Promise<Result<readonly RecallHit[], MemoryError>>;
39
54
  /**
40
55
  * Append one entry to the run's hash-chained log. The implementation
41
56
  * assigns `sequence` and `prevHash` / `entryHash` atomically; the
@@ -53,8 +68,15 @@ export interface MemoryQueryBinding {
53
68
  export interface ListFactsInput {
54
69
  readonly tenantId: TenantId;
55
70
  readonly type?: string;
71
+ /** Narrows within what `readers` may see: every given key must match. */
56
72
  readonly scope?: Partial<MemoryScope>;
73
+ /**
74
+ * What the reader may see (the scope guard), applied inside the query
75
+ * before any limit. Absent: only tenant-wide facts.
76
+ */
77
+ readonly readers?: MemoryReaders;
57
78
  readonly limit?: number;
79
+ /** Ignored: a list holds each fact's current revision. */
58
80
  readonly latestOnly?: boolean;
59
81
  }
60
82
  export interface SearchByKeywordInput {
@@ -62,6 +84,11 @@ export interface SearchByKeywordInput {
62
84
  readonly query: string;
63
85
  readonly type?: string;
64
86
  readonly scope?: Partial<MemoryScope>;
87
+ /**
88
+ * What the reader may see (the scope guard), applied inside the query
89
+ * before any limit. Absent: only tenant-wide facts.
90
+ */
91
+ readonly readers?: MemoryReaders;
65
92
  readonly topK?: number;
66
93
  }
67
94
  export interface SearchBySemanticInput {
@@ -75,6 +102,11 @@ export interface SearchBySemanticInput {
75
102
  readonly embeddingModel?: string;
76
103
  readonly type?: string;
77
104
  readonly scope?: Partial<MemoryScope>;
105
+ /**
106
+ * What the reader may see (the scope guard), applied inside the query
107
+ * before any limit. Absent: only tenant-wide facts.
108
+ */
109
+ readonly readers?: MemoryReaders;
78
110
  readonly topK?: number;
79
111
  }
80
112
  export interface AppendLogInput {
@@ -1 +1 @@
1
- {"version":3,"file":"memory-binding.d.ts","sourceRoot":"","sources":["../src/memory-binding.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"memory-binding.d.ts","sourceRoot":"","sources":["../src/memory-binding.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { MemoryReaders, MemoryScope } from './types.js';
2
+ /**
3
+ * Whether `readers` may see a fact in `scope`: the scope guard, as every
4
+ * memory binding applies it inside its queries (a SQL binding's guard
5
+ * must agree with this one, case for case).
6
+ *
7
+ * Each container the scope names must be one the readers have:
8
+ * - its project (or one they act in for all end users,
9
+ * `onBehalfOfProjectIds`);
10
+ * - its org, for an org-wide fact (no project);
11
+ * - its user;
12
+ * - its participant, or the project on behalf of all of them;
13
+ * - its thread, or the project on behalf of all of them.
14
+ * A fact naming none of them is tenant-wide: every reader sees it. The
15
+ * session is not a container.
16
+ */
17
+ export declare function isReadableBy(scope: MemoryScope, readers: MemoryReaders): boolean;
18
+ //# sourceMappingURL=readers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readers.d.ts","sourceRoot":"","sources":["../src/readers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE7D;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAoBhF"}
@@ -0,0 +1,40 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ /**
4
+ * Whether `readers` may see a fact in `scope`: the scope guard, as every
5
+ * memory binding applies it inside its queries (a SQL binding's guard
6
+ * must agree with this one, case for case).
7
+ *
8
+ * Each container the scope names must be one the readers have:
9
+ * - its project (or one they act in for all end users,
10
+ * `onBehalfOfProjectIds`);
11
+ * - its org, for an org-wide fact (no project);
12
+ * - its user;
13
+ * - its participant, or the project on behalf of all of them;
14
+ * - its thread, or the project on behalf of all of them.
15
+ * A fact naming none of them is tenant-wide: every reader sees it. The
16
+ * session is not a container.
17
+ */
18
+ export function isReadableBy(scope, readers) {
19
+ if (readers.all === true)
20
+ return true;
21
+ const project = scope.projectId;
22
+ const has = (ids, id) => ids?.includes(id) === true;
23
+ const onBehalf = project !== undefined && has(readers.onBehalfOfProjectIds, project);
24
+ if (project !== undefined && !(has(readers.projectIds, project) || onBehalf))
25
+ return false;
26
+ if (project === undefined && scope.orgId !== undefined && !has(readers.orgIds, scope.orgId)) {
27
+ return false;
28
+ }
29
+ if (scope.userId !== undefined && !has(readers.userIds, scope.userId))
30
+ return false;
31
+ if (scope.participantId !== undefined &&
32
+ !(has(readers.participantIds, scope.participantId) || onBehalf)) {
33
+ return false;
34
+ }
35
+ if (scope.threadId !== undefined && !(has(readers.threadIds, scope.threadId) || onBehalf)) {
36
+ return false;
37
+ }
38
+ return true;
39
+ }
40
+ //# sourceMappingURL=readers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readers.js","sourceRoot":"","sources":["../src/readers.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC;AAIjC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,YAAY,CAAC,KAAkB,EAAE,OAAsB;IACrE,IAAI,OAAO,CAAC,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,CAAC;IAChC,MAAM,GAAG,GAAG,CAAI,GAA6B,EAAE,EAAK,EAAE,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC;IACpF,MAAM,QAAQ,GAAG,OAAO,KAAK,SAAS,IAAI,GAAG,CAAC,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC;IACrF,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,IAAI,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAC3F,IAAI,OAAO,KAAK,SAAS,IAAI,KAAK,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5F,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,KAAK,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IACpF,IACE,KAAK,CAAC,aAAa,KAAK,SAAS;QACjC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,KAAK,CAAC,aAAa,CAAC,IAAI,QAAQ,CAAC,EAC/D,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,IAAI,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,SAAS,EAAE,KAAK,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,EAAE,CAAC;QAC1F,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,100 @@
1
+ import type { EmbeddingProviderRegistry } from '@kindgi/embedding';
2
+ import type { ScopeSegment, TenantId, Timestamp } from '@kindgi/types';
3
+ import type { MemoryReaders } from './types.js';
4
+ /**
5
+ * One message of an earlier conversation, as recall finds it: a user's
6
+ * message or an agent's answer (tool calls and the turns that made them
7
+ * are not indexed), with the indexed messages either side for context.
8
+ */
9
+ export interface RecalledMessage {
10
+ readonly conversationId: string;
11
+ readonly sequence: number;
12
+ readonly role: 'user' | 'agent';
13
+ readonly text: string;
14
+ readonly createdAt: Timestamp;
15
+ /** The agent the conversation was with. */
16
+ readonly agentId: string;
17
+ readonly projectId?: string;
18
+ /** The conversation's end user (the app's own id for them). */
19
+ readonly participantId?: string;
20
+ /** The Kindgi user its turns acted for, when one did. */
21
+ readonly userId?: string;
22
+ /** The indexed message (of the roles recalled) just before it in its conversation, if any. */
23
+ readonly before?: {
24
+ readonly role: 'user' | 'agent';
25
+ readonly text: string;
26
+ };
27
+ /** The indexed message (of the roles recalled) just after it, if any. */
28
+ readonly after?: {
29
+ readonly role: 'user' | 'agent';
30
+ readonly text: string;
31
+ };
32
+ }
33
+ /** A recalled message and how well it matched (a full-text rank or a cosine similarity). */
34
+ export interface RecallHit {
35
+ readonly message: RecalledMessage;
36
+ readonly score?: number;
37
+ }
38
+ /**
39
+ * What one recall narrows to, within what the readers may see. Always
40
+ * one agent's conversations. Every other field given must match.
41
+ */
42
+ export interface RecallSelection {
43
+ readonly agentId: string;
44
+ /** Only this conversation (with `beforeSequence`: its messages older than that). */
45
+ readonly conversationId?: string;
46
+ readonly beforeSequence?: number;
47
+ /** Every conversation but this one. */
48
+ readonly excludeConversationId?: string;
49
+ readonly participantId?: string;
50
+ readonly userId?: string;
51
+ readonly projectId?: string;
52
+ /** Conversations whose segment path starts with this one (the same customer). */
53
+ readonly segmentsPrefix?: readonly ScopeSegment[];
54
+ }
55
+ export interface SearchConversationsInput {
56
+ readonly tenantId: TenantId;
57
+ /** What the reader may see (`isRecallReadableBy`), applied in the query before the limit. */
58
+ readonly readers: MemoryReaders;
59
+ /** The narrowings, merged: a message matching any of them. */
60
+ readonly selections: readonly RecallSelection[];
61
+ /** `list`: the newest first, no query. `keyword`: full-text. `semantic`: by meaning. */
62
+ readonly mode: 'list' | 'keyword' | 'semantic';
63
+ /**
64
+ * Whose messages: the hits and their neighbours alike. Default
65
+ * `['user']`, the people's own words; an agent's earlier answers only
66
+ * when asked for.
67
+ */
68
+ readonly roles?: readonly ('user' | 'agent')[];
69
+ readonly query?: string;
70
+ /** For `semantic`: the registry the query is embedded with. */
71
+ readonly embeddingRegistry?: EmbeddingProviderRegistry;
72
+ readonly embeddingModel?: string;
73
+ readonly topK: number;
74
+ }
75
+ /** The containers a recalled message's conversation is in, as the recall guard sees them. */
76
+ export interface RecallRow {
77
+ readonly conversationId: string;
78
+ readonly projectId?: string;
79
+ readonly participantId?: string;
80
+ readonly userId?: string;
81
+ }
82
+ /**
83
+ * Whether `readers` may recall a message of this conversation: the recall
84
+ * guard, as every binding applies it inside its query (a SQL binding's
85
+ * guard must agree with this one, case for case). Stricter than facts'
86
+ * (`isReadableBy`): a conversation is always someone's.
87
+ * - **Its project:** one the readers have, or act in for every end user
88
+ * (`onBehalfOfProjectIds`). A conversation without a project passes
89
+ * only by its person or the conversation itself.
90
+ * - **Its person:** its end user when it has one, else the Kindgi user
91
+ * its turns acted for. The readers must be that person
92
+ * (`participantIds`, or `userIds` for a conversation without an end
93
+ * user), be in the conversation (`threadIds`), or act in its project
94
+ * for every end user. An app's credential is one Kindgi user for all
95
+ * of its end users, so the user never opens an end user's
96
+ * conversation. A conversation naming no person is readable only
97
+ * from inside it, or for its whole project.
98
+ */
99
+ export declare function isRecallReadableBy(row: RecallRow, readers: MemoryReaders): boolean;
100
+ //# sourceMappingURL=recall.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recall.d.ts","sourceRoot":"","sources":["../src/recall.ts"],"names":[],"mappings":"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"}
package/dist/recall.js ADDED
@@ -0,0 +1,37 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ /**
4
+ * Whether `readers` may recall a message of this conversation: the recall
5
+ * guard, as every binding applies it inside its query (a SQL binding's
6
+ * guard must agree with this one, case for case). Stricter than facts'
7
+ * (`isReadableBy`): a conversation is always someone's.
8
+ * - **Its project:** one the readers have, or act in for every end user
9
+ * (`onBehalfOfProjectIds`). A conversation without a project passes
10
+ * only by its person or the conversation itself.
11
+ * - **Its person:** its end user when it has one, else the Kindgi user
12
+ * its turns acted for. The readers must be that person
13
+ * (`participantIds`, or `userIds` for a conversation without an end
14
+ * user), be in the conversation (`threadIds`), or act in its project
15
+ * for every end user. An app's credential is one Kindgi user for all
16
+ * of its end users, so the user never opens an end user's
17
+ * conversation. A conversation naming no person is readable only
18
+ * from inside it, or for its whole project.
19
+ */
20
+ export function isRecallReadableBy(row, readers) {
21
+ if (readers.all === true)
22
+ return true;
23
+ const has = (ids, id) => id !== undefined && ids?.includes(id) === true;
24
+ const project = row.projectId;
25
+ const onBehalf = has(readers.onBehalfOfProjectIds, project);
26
+ if (project !== undefined &&
27
+ !(has(readers.projectIds, project) || onBehalf)) {
28
+ return false;
29
+ }
30
+ const isPerson = row.participantId !== undefined
31
+ ? has(readers.participantIds, row.participantId)
32
+ : has(readers.userIds, row.userId);
33
+ return (isPerson ||
34
+ has(readers.threadIds, row.conversationId) ||
35
+ onBehalf);
36
+ }
37
+ //# sourceMappingURL=recall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"recall.js","sourceRoot":"","sources":["../src/recall.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC;AAoFjC;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAc,EAAE,OAAsB;IACvE,IAAI,OAAO,CAAC,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,GAAG,GAAG,CAAI,GAA6B,EAAE,EAAiB,EAAE,EAAE,CAClE,EAAE,KAAK,SAAS,IAAI,GAAG,EAAE,QAAQ,CAAC,EAAE,CAAC,KAAK,IAAI,CAAC;IACjD,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,CAAC;IAC9B,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,oBAAqD,EAAE,OAAO,CAAC,CAAC;IAC7F,IACE,OAAO,KAAK,SAAS;QACrB,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,UAA2C,EAAE,OAAO,CAAC,IAAI,QAAQ,CAAC,EAChF,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,MAAM,QAAQ,GACZ,GAAG,CAAC,aAAa,KAAK,SAAS;QAC7B,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC,aAAa,CAAC;QAChD,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAwC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACxE,OAAO,CACL,QAAQ;QACR,GAAG,CAAC,OAAO,CAAC,SAA0C,EAAE,GAAG,CAAC,cAAc,CAAC;QAC3E,QAAQ,CACT,CAAC;AACJ,CAAC"}
@@ -0,0 +1,76 @@
1
+ import type { Result, TenantId, Timestamp } from '@kindgi/types';
2
+ import type { MemoryError } from './errors.js';
3
+ import type { Fact, FactSubject, MemoryScope } from './types.js';
4
+ /**
5
+ * What an agent remembers through its `remember` tool: a short text, and
6
+ * optionally the slot (`key`) it fills. A new value for a slot the same
7
+ * agent filled before, for the same type and scope, is that fact's next
8
+ * revision.
9
+ */
10
+ export interface RememberedContent {
11
+ readonly text: string;
12
+ readonly key?: string;
13
+ }
14
+ /** Why a remembered fact waits for a person before any read sees it. */
15
+ export type RememberReviewReason =
16
+ /** The declared scope reaches beyond one person (`same-project`, `tenant`). */
17
+ 'wide-scope'
18
+ /** The text reads like an instruction (always/never/ignore, a URL, a tool name). */
19
+ | 'instruction-like';
20
+ /**
21
+ * One `remember` call, as the agent layer builds it from the agent's
22
+ * declaration and the run. The model chooses only the type (among those
23
+ * declared), the text, the slot and how long it's true; never the scope,
24
+ * the trust or whom it's attributed to.
25
+ */
26
+ export interface RememberFactInput {
27
+ readonly tenantId: TenantId;
28
+ /** Where it's stored: the declaration's scope, filled from the run. */
29
+ readonly scope: MemoryScope;
30
+ readonly type: string;
31
+ readonly content: RememberedContent;
32
+ /** Whom it's about: the conversation's end user, else the run's user. */
33
+ readonly subjects: readonly FactSubject[];
34
+ /** The agent version that remembered it. */
35
+ readonly agent: {
36
+ readonly id: string;
37
+ readonly version: string;
38
+ };
39
+ /**
40
+ * The call that wrote it. A second call with the same run and tool call
41
+ * (a step re-run after a crash) returns the fact the first one wrote.
42
+ */
43
+ readonly generatedBy: {
44
+ readonly runId: string;
45
+ readonly stepId?: string;
46
+ readonly toolCallId: string;
47
+ };
48
+ /** How long it's kept unless a person verifies it (retention `keepDays`). */
49
+ readonly keepDays: number;
50
+ /** When it stops being true in the world, if the model said so. */
51
+ readonly validUntil?: Timestamp;
52
+ /** Present when a person must approve it first; no read sees it until then. */
53
+ readonly review?: {
54
+ readonly reasons: readonly RememberReviewReason[];
55
+ };
56
+ }
57
+ export interface RememberFactResult {
58
+ /** The revision written: `trust: unverified`, `review: pending` while it waits. */
59
+ readonly fact: Fact<RememberedContent>;
60
+ /**
61
+ * `created`: a new fact. `superseded`: the next revision of the fact
62
+ * that held the slot. `replayed`: this call had already written it.
63
+ */
64
+ readonly outcome: 'created' | 'superseded' | 'replayed';
65
+ /** The approval a pending fact waits on. */
66
+ readonly approvalId?: string;
67
+ }
68
+ /**
69
+ * Agent memory writes (the `remember` tool). Optional on the agent
70
+ * bindings: a host without it offers the tool, and a call says it
71
+ * can't remember.
72
+ */
73
+ export interface MemoryRememberBinding {
74
+ remember(input: RememberFactInput): Promise<Result<RememberFactResult, MemoryError>>;
75
+ }
76
+ //# sourceMappingURL=remember.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remember.d.ts","sourceRoot":"","sources":["../src/remember.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAEjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEjE;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,wEAAwE;AACxE,MAAM,MAAM,oBAAoB;AAC9B,+EAA+E;AAC7E,YAAY;AACd,oFAAoF;GAClF,kBAAkB,CAAC;AAEvB;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,iBAAiB,CAAC;IACpC,yEAAyE;IACzE,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,4CAA4C;IAC5C,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAClE;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE;QACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QACzB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;KAC7B,CAAC;IACF,6EAA6E;IAC7E,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,CAAC;IAChC,+EAA+E;IAC/E,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,oBAAoB,EAAE,CAAA;KAAE,CAAC;CACzE;AAED,MAAM,WAAW,kBAAkB;IACjC,mFAAmF;IACnF,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;IACvC;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,SAAS,GAAG,YAAY,GAAG,UAAU,CAAC;IACxD,4CAA4C;IAC5C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC,CAAC;CACtF"}
@@ -0,0 +1,4 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (C) 2026 Kindgi Inc.
3
+ export {};
4
+ //# sourceMappingURL=remember.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remember.js","sourceRoot":"","sources":["../src/remember.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,iCAAiC"}