@knolo/core 3.2.1 → 3.2.4

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 CHANGED
@@ -309,6 +309,74 @@ Properties:
309
309
 
310
310
  ---
311
311
 
312
+ # 🧠 Knolo Cortex
313
+
314
+ Knolo Cortex is a local-first overlay memory layer for `.knolo` packs.
315
+
316
+ It gives you:
317
+
318
+ * Deterministic append-only memory writes
319
+ * Lexical-first recall with label and namespace filters
320
+ * Portable memory logs you can serialize and replay
321
+ * Consolidation back into pack docs without mutating the pack itself
322
+ * Deterministic graph export via `memoryToClaimOps()`
323
+
324
+ ## Example
325
+
326
+ ```ts
327
+ import {
328
+ buildPack,
329
+ consolidateMemories,
330
+ createCortex,
331
+ mountPack,
332
+ recall,
333
+ remember,
334
+ } from "@knolo/core";
335
+
336
+ const cortex = createCortex({ actor: "notes-app" });
337
+ const { cortex: next, memory } = remember(cortex, {
338
+ kind: "note",
339
+ text: "Project alpha uses a local-first memory overlay.",
340
+ labels: ["project.alpha"],
341
+ namespace: "project.alpha",
342
+ });
343
+
344
+ const hits = recall(next, "project alpha");
345
+ const docs = consolidateMemories(next, { namespacePrefix: "memory" });
346
+ const bytes = await buildPack(docs);
347
+ const pack = await mountPack({ src: bytes });
348
+ ```
349
+
350
+ If you need to load a local file in Node, use `@knolo/core/node` or read the bytes first and pass a `Uint8Array` into `mountPack()`.
351
+
352
+ ## Cortex API
353
+
354
+ ```ts
355
+ import {
356
+ createCortex,
357
+ remember,
358
+ forget,
359
+ labelMemory,
360
+ linkMemories,
361
+ recall,
362
+ consolidateMemories,
363
+ memoryToClaimOps,
364
+ } from "@knolo/core";
365
+ ```
366
+
367
+ * `createCortex({ actor?, now?, log? })` creates an immutable memory runtime
368
+ * `remember()` appends a new memory entry
369
+ * `forget()` tombstones a memory
370
+ * `labelMemory()` adds labels without mutating the original cortex
371
+ * `linkMemories()` records deterministic memory relationships
372
+ * `recall()` ranks memories with lexical-first scoring
373
+ * `consolidateMemories()` converts selected memories back into `BuildInputDoc[]`
374
+ * `memoryToClaimOps()` emits deterministic ClaimGraph ops for memory nodes, labels, and links
375
+
376
+ The full example lives in [`examples/memory-overlay/README.md`](../../examples/memory-overlay/README.md).
377
+
378
+ ---
379
+
312
380
  # 🗺 Roadmap
313
381
 
314
382
  * Incremental pack updates
@@ -388,4 +456,3 @@ Runtimes that ignore unknown trailing bytes remain compatible.
388
456
  # 📄 License
389
457
 
390
458
  Apache-2.0
391
-
package/dist/index.d.ts CHANGED
@@ -3,13 +3,19 @@ export { query, lexConfidence, validateQueryOptions, validateSemanticQueryOption
3
3
  export { makeContextPatch } from './patch.js';
4
4
  export { buildPack } from './builder.js';
5
5
  export { quantizeEmbeddingInt8L2Norm, encodeScaleF16, decodeScaleF16, } from './semantic.js';
6
+ export { cosineSimilarity, normalizeVector } from './semantic/cosine.js';
7
+ export { createPackFingerprint, serializeSidecar, parseSidecar, validateSidecarForPack, } from './semantic/sidecar.js';
8
+ export { rerankCandidates } from './semantic/rerank.js';
9
+ export { assertProviderCompatible, ensureProviderModelId } from './semantic/provider.js';
6
10
  export { listAgents, getAgent, resolveAgent, buildSystemPrompt, isToolAllowed, assertToolAllowed, validateAgentRegistry, validateAgentDefinition, } from './agent.js';
7
11
  export { getClaimGraph, validateClaimGraph, } from './graph/claim_graph.js';
8
12
  export { buildClaimGraph } from './graph/build_claim_graph.js';
9
13
  export { createGraphLog, appendOp, applyClaimGraphLog, mergeClaimGraphLogs, serializeClaimGraphLog, deserializeClaimGraphLog, } from './graph/log.js';
10
14
  export { expandQueryWithGraph } from './graph/query_expand.js';
15
+ export * from './memory/index.js';
11
16
  export type { MountOptions, PackMeta, Pack } from './pack.runtime.js';
12
17
  export type { QueryOptions, Hit } from './query.js';
18
+ export type { EmbeddingProvider, SemanticSidecar, SemanticQueryOptions, RetrievalEvidence } from './semantic/types.js';
13
19
  export type { ContextPatch } from './patch.js';
14
20
  export type { BuildInputDoc, BuildPackOptions } from './builder.js';
15
21
  export type { AgentPromptTemplate, AgentToolPolicy, AgentRetrievalDefaults, AgentDefinitionV1, AgentRegistry, ResolveAgentInput, ResolvedAgent, } from './agent.js';
package/dist/index.js CHANGED
@@ -4,11 +4,16 @@ export { query, lexConfidence, validateQueryOptions, validateSemanticQueryOption
4
4
  export { makeContextPatch } from './patch.js';
5
5
  export { buildPack } from './builder.js';
6
6
  export { quantizeEmbeddingInt8L2Norm, encodeScaleF16, decodeScaleF16, } from './semantic.js';
7
+ export { cosineSimilarity, normalizeVector } from './semantic/cosine.js';
8
+ export { createPackFingerprint, serializeSidecar, parseSidecar, validateSidecarForPack, } from './semantic/sidecar.js';
9
+ export { rerankCandidates } from './semantic/rerank.js';
10
+ export { assertProviderCompatible, ensureProviderModelId } from './semantic/provider.js';
7
11
  export { listAgents, getAgent, resolveAgent, buildSystemPrompt, isToolAllowed, assertToolAllowed, validateAgentRegistry, validateAgentDefinition, } from './agent.js';
8
12
  export { getClaimGraph, validateClaimGraph, } from './graph/claim_graph.js';
9
13
  export { buildClaimGraph } from './graph/build_claim_graph.js';
10
14
  export { createGraphLog, appendOp, applyClaimGraphLog, mergeClaimGraphLogs, serializeClaimGraphLog, deserializeClaimGraphLog, } from './graph/log.js';
11
15
  export { expandQueryWithGraph } from './graph/query_expand.js';
16
+ export * from './memory/index.js';
12
17
  export { parseToolCallV1FromText } from './tool_parse.js';
13
18
  export { nowIso, createTrace } from './trace.js';
14
19
  export { assertToolCallAllowed } from './tool_gate.js';
package/dist/indexer.d.ts CHANGED
@@ -13,11 +13,12 @@ export type IndexBuildResult = {
13
13
  * sequences of blockId and positions for that term, with zeros as delimiters.
14
14
  * The structure looks like:
15
15
  *
16
- * [termId, blockId+1, pos, pos, 0, blockId+1, pos, 0, 0, termId, ...]
16
+ * [termId, blockId+1, pos+1, pos+1, 0, blockId+1, pos+1, 0, 0, termId, ...]
17
17
  *
18
18
  * Block IDs are stored as bid+1 so that 0 can remain a sentinel delimiter.
19
- * Each block section ends with a 0, and each term section ends with a 0. The
20
- * entire array can be streamed sequentially without needing to know the sizes
21
- * of individual lists ahead of time.
19
+ * Positions are also stored as pos+1 for the same reason. Each block section
20
+ * ends with a 0, and each term section ends with a 0. The entire array can be
21
+ * streamed sequentially without needing to know the sizes of individual lists
22
+ * ahead of time.
22
23
  */
23
24
  export declare function buildIndex(blocks: Block[]): IndexBuildResult;
package/dist/indexer.js CHANGED
@@ -14,12 +14,13 @@ import { tokenize } from "./tokenize.js";
14
14
  * sequences of blockId and positions for that term, with zeros as delimiters.
15
15
  * The structure looks like:
16
16
  *
17
- * [termId, blockId+1, pos, pos, 0, blockId+1, pos, 0, 0, termId, ...]
17
+ * [termId, blockId+1, pos+1, pos+1, 0, blockId+1, pos+1, 0, 0, termId, ...]
18
18
  *
19
19
  * Block IDs are stored as bid+1 so that 0 can remain a sentinel delimiter.
20
- * Each block section ends with a 0, and each term section ends with a 0. The
21
- * entire array can be streamed sequentially without needing to know the sizes
22
- * of individual lists ahead of time.
20
+ * Positions are also stored as pos+1 for the same reason. Each block section
21
+ * ends with a 0, and each term section ends with a 0. The entire array can be
22
+ * streamed sequentially without needing to know the sizes of individual lists
23
+ * ahead of time.
23
24
  */
24
25
  export function buildIndex(blocks) {
25
26
  // Map term to termId and interim map of termId -> blockId -> positions
@@ -61,7 +62,7 @@ export function buildIndex(blocks) {
61
62
  for (const [tid, blockMap] of termBlockPositions) {
62
63
  postings.push(tid);
63
64
  for (const [bid, positions] of blockMap) {
64
- postings.push(bid + 1, ...positions, 0);
65
+ postings.push(bid + 1, ...positions.map((pos) => pos + 1), 0);
65
66
  }
66
67
  postings.push(0); // end of term
67
68
  }
@@ -0,0 +1,15 @@
1
+ import type { BuildInputDoc } from '../builder.js';
2
+ import type { CortexV1 } from './cortex.js';
3
+ import type { MemoryEngramV1 } from './engram.js';
4
+ export type ConsolidateMemoriesOptionsV1 = {
5
+ namespacePrefix?: string;
6
+ kind?: string | readonly string[];
7
+ labels?: string | readonly string[];
8
+ namespace?: string | readonly string[];
9
+ minImportance?: number;
10
+ minConfidence?: number;
11
+ minAgeMs?: number;
12
+ maxAgeMs?: number;
13
+ now?: number;
14
+ };
15
+ export declare function consolidateMemories(cortexOrMemories: CortexV1 | readonly MemoryEngramV1[], opts?: ConsolidateMemoriesOptionsV1): BuildInputDoc[];
@@ -0,0 +1,71 @@
1
+ import { matchesMemoryLabels, validateMemoryLabels } from './label.js';
2
+ import { normalizeMemoryLabel } from './label.js';
3
+ import { normalize } from '../tokenize.js';
4
+ export function consolidateMemories(cortexOrMemories, opts = {}) {
5
+ const memories = isCortex(cortexOrMemories)
6
+ ? cortexOrMemories.memories
7
+ : cortexOrMemories;
8
+ const now = opts.now ?? (isCortex(cortexOrMemories) ? cortexOrMemories.now() : Date.now());
9
+ const namespacePrefix = normalizeNamespacePrefix(opts.namespacePrefix);
10
+ const kindFilters = normalizeKindFilters(opts.kind);
11
+ const labelsFilter = validateMemoryLabels(opts.labels);
12
+ const namespaceFilters = normalizeNamespaceFilters(opts.namespace);
13
+ return memories
14
+ .filter((memory) => {
15
+ if (kindFilters.length > 0 && !kindFilters.includes(normalizeKind(memory.kind)))
16
+ return false;
17
+ if (labelsFilter.length > 0 && !matchesMemoryLabels(memory.labels, labelsFilter))
18
+ return false;
19
+ if (namespaceFilters.length > 0 && !matchesNamespace(memory.namespace, namespaceFilters))
20
+ return false;
21
+ if (opts.minImportance !== undefined && valueOrDefault(memory.importance, 0.5) < opts.minImportance)
22
+ return false;
23
+ if (opts.minConfidence !== undefined && valueOrDefault(memory.confidence, 0.5) < opts.minConfidence)
24
+ return false;
25
+ const ageMs = now - memory.ts;
26
+ if (opts.minAgeMs !== undefined && ageMs < opts.minAgeMs)
27
+ return false;
28
+ if (opts.maxAgeMs !== undefined && ageMs > opts.maxAgeMs)
29
+ return false;
30
+ return true;
31
+ })
32
+ .slice()
33
+ .sort((a, b) => a.ts - b.ts || a.id.localeCompare(b.id))
34
+ .map((memory) => ({
35
+ id: memory.id,
36
+ heading: `${memory.kind}: ${memory.labels.join('/')}`,
37
+ namespace: `${namespacePrefix}.${memory.kind}`,
38
+ text: memory.text,
39
+ }));
40
+ }
41
+ function isCortex(input) {
42
+ return !Array.isArray(input) && typeof input === 'object' && input !== null && 'memories' in input;
43
+ }
44
+ function normalizeNamespacePrefix(value) {
45
+ const normalized = normalizeMemoryLabel(value ?? 'memory');
46
+ return normalized || 'memory';
47
+ }
48
+ function normalizeKindFilters(kind) {
49
+ if (kind === undefined)
50
+ return [];
51
+ const values = Array.isArray(kind) ? kind : [kind];
52
+ return [...new Set(values.map(normalizeKind).filter(Boolean))].sort((a, b) => a.localeCompare(b));
53
+ }
54
+ function normalizeNamespaceFilters(value) {
55
+ if (value === undefined)
56
+ return [];
57
+ const values = Array.isArray(value) ? value : [value];
58
+ return [...new Set(values.map((entry) => normalizeMemoryLabel(entry)).filter(Boolean))].sort((a, b) => a.localeCompare(b));
59
+ }
60
+ function normalizeKind(kind) {
61
+ return normalize(kind).replace(/\s+/g, ' ').trim();
62
+ }
63
+ function matchesNamespace(value, filters) {
64
+ if (!value)
65
+ return false;
66
+ const normalized = normalizeMemoryLabel(value);
67
+ return filters.some((filter) => normalized === filter || normalized.startsWith(`${filter}.`));
68
+ }
69
+ function valueOrDefault(value, fallback) {
70
+ return Number.isFinite(value) ? value : fallback;
71
+ }
@@ -0,0 +1,43 @@
1
+ import type { MemoryEngramV1, MemoryInputV1, MemoryLinkV1 } from './engram.js';
2
+ import { type MemoryLogV1, type MemoryOpV1 } from './log.js';
3
+ export type CortexV1 = {
4
+ version: 1;
5
+ actor: string;
6
+ now: () => number;
7
+ log: MemoryLogV1;
8
+ memories: MemoryEngramV1[];
9
+ };
10
+ export type CortexWriteResult<T extends object> = T & {
11
+ cortex: CortexV1;
12
+ };
13
+ export declare function createCortex(opts?: {
14
+ actor?: string;
15
+ now?: () => number;
16
+ log?: MemoryLogV1;
17
+ }): CortexV1;
18
+ export declare function remember(cortex: CortexV1, input: MemoryInputV1): CortexWriteResult<{
19
+ memory: MemoryEngramV1;
20
+ op: MemoryOpV1;
21
+ }>;
22
+ export declare function forget(cortex: CortexV1, id: string, provenance?: {
23
+ ts?: number;
24
+ actor?: string;
25
+ }): CortexWriteResult<{
26
+ memoryId: string;
27
+ op: MemoryOpV1;
28
+ }>;
29
+ export declare function labelMemory(cortex: CortexV1, id: string, labels: string | readonly string[], provenance?: {
30
+ ts?: number;
31
+ actor?: string;
32
+ }): CortexWriteResult<{
33
+ memory?: MemoryEngramV1;
34
+ op: MemoryOpV1;
35
+ }>;
36
+ export declare function linkMemories(cortex: CortexV1, from: string, to: string, relation: string, provenance?: {
37
+ ts?: number;
38
+ actor?: string;
39
+ confidence?: number;
40
+ }): CortexWriteResult<{
41
+ link: MemoryLinkV1;
42
+ op: MemoryOpV1;
43
+ }>;
@@ -0,0 +1,93 @@
1
+ import { createMemoryId, normalizeMemoryActor, normalizeMemoryInput, normalizeMemoryKind, normalizeMemoryTimestamp, } from './engram.js';
2
+ import { appendMemoryOp, applyMemoryLog, createMemoryLog, } from './log.js';
3
+ import { validateMemoryLabels } from './label.js';
4
+ export function createCortex(opts = {}) {
5
+ const log = opts.log ? { version: 1, ops: [...opts.log.ops] } : createMemoryLog();
6
+ return {
7
+ version: 1,
8
+ actor: normalizeMemoryActor(opts.actor ?? 'cortex'),
9
+ now: opts.now ?? (() => Date.now()),
10
+ log,
11
+ memories: applyMemoryLog(log),
12
+ };
13
+ }
14
+ export function remember(cortex, input) {
15
+ const memory = normalizeMemoryInput(input, {
16
+ actor: cortex.actor,
17
+ ts: cortex.now(),
18
+ });
19
+ const op = {
20
+ op: 'remember',
21
+ ts: memory.ts,
22
+ actor: memory.actor,
23
+ memory,
24
+ };
25
+ return applyWrite(cortex, op, { memory });
26
+ }
27
+ export function forget(cortex, id, provenance = {}) {
28
+ const op = {
29
+ op: 'forget',
30
+ id,
31
+ ts: normalizeMemoryTimestamp(provenance.ts ?? cortex.now()),
32
+ actor: normalizeMemoryActor(provenance.actor ?? cortex.actor),
33
+ };
34
+ return applyWrite(cortex, op, { memoryId: id });
35
+ }
36
+ export function labelMemory(cortex, id, labels, provenance = {}) {
37
+ const normalizedLabels = validateMemoryLabels(labels);
38
+ const op = {
39
+ op: 'label',
40
+ id,
41
+ labels: normalizedLabels,
42
+ ts: normalizeMemoryTimestamp(provenance.ts ?? cortex.now()),
43
+ actor: normalizeMemoryActor(provenance.actor ?? cortex.actor),
44
+ };
45
+ return applyWrite(cortex, op, {
46
+ memory: cortex.memories.find((memory) => memory.id === id),
47
+ });
48
+ }
49
+ export function linkMemories(cortex, from, to, relation, provenance = {}) {
50
+ const normalizedRelation = normalizeMemoryKind(relation);
51
+ const ts = normalizeMemoryTimestamp(provenance.ts ?? cortex.now());
52
+ const actor = normalizeMemoryActor(provenance.actor ?? cortex.actor);
53
+ const link = {
54
+ version: 1,
55
+ id: createMemoryId({
56
+ kind: 'link',
57
+ text: [from, normalizedRelation, to, provenance.confidence ?? ''].join('\u0001'),
58
+ ts,
59
+ actor,
60
+ }),
61
+ from,
62
+ to,
63
+ relation: normalizedRelation,
64
+ ts,
65
+ actor,
66
+ confidence: provenance.confidence,
67
+ };
68
+ const op = {
69
+ op: 'link',
70
+ from,
71
+ to,
72
+ relation: normalizedRelation,
73
+ confidence: provenance.confidence,
74
+ ts,
75
+ actor,
76
+ };
77
+ return applyWrite(cortex, op, { link });
78
+ }
79
+ function applyWrite(cortex, op, extra) {
80
+ const log = appendMemoryOp(cortex.log, op);
81
+ const memories = applyMemoryLog(log);
82
+ return {
83
+ ...extra,
84
+ op,
85
+ cortex: {
86
+ version: 1,
87
+ actor: cortex.actor,
88
+ now: cortex.now,
89
+ log,
90
+ memories,
91
+ },
92
+ };
93
+ }
@@ -0,0 +1,48 @@
1
+ export type MemoryKind = string;
2
+ export type MemoryLinkV1 = {
3
+ version: 1;
4
+ id: string;
5
+ from: string;
6
+ to: string;
7
+ relation: string;
8
+ ts: number;
9
+ actor: string;
10
+ confidence?: number;
11
+ };
12
+ export type MemoryEngramV1 = {
13
+ version: 1;
14
+ id: string;
15
+ kind: MemoryKind;
16
+ text: string;
17
+ labels: string[];
18
+ namespace?: string;
19
+ source?: string;
20
+ importance?: number;
21
+ confidence?: number;
22
+ ts: number;
23
+ actor: string;
24
+ links: MemoryLinkV1[];
25
+ };
26
+ export type MemoryInputV1 = {
27
+ kind: MemoryKind;
28
+ text: string;
29
+ labels?: string | readonly string[];
30
+ namespace?: string;
31
+ source?: string;
32
+ importance?: number;
33
+ confidence?: number;
34
+ ts?: number;
35
+ actor?: string;
36
+ };
37
+ export type MemoryProvenanceV1 = {
38
+ ts?: number;
39
+ actor?: string;
40
+ };
41
+ export declare function createMemoryId(input: Pick<MemoryEngramV1, 'kind' | 'text' | 'ts' | 'actor'>): string;
42
+ export declare function normalizeMemoryInput(input: MemoryInputV1, provenance?: MemoryProvenanceV1): MemoryEngramV1;
43
+ export declare function normalizeMemoryKind(kind: string): string;
44
+ export declare function normalizeMemoryText(text: string): string;
45
+ export declare function normalizeMemoryNamespace(namespace?: string): string | undefined;
46
+ export declare function normalizeMemorySource(source?: string): string | undefined;
47
+ export declare function normalizeMemoryActor(actor: string): string;
48
+ export declare function normalizeMemoryTimestamp(ts: number): number;
@@ -0,0 +1,90 @@
1
+ import { normalize } from '../tokenize.js';
2
+ import { normalizeMemoryLabel, validateMemoryLabels } from './label.js';
3
+ export function createMemoryId(input) {
4
+ const payload = [
5
+ normalizeMemoryKind(input.kind),
6
+ normalizeMemoryTextForId(input.text),
7
+ normalizeMemoryTimestamp(input.ts),
8
+ normalizeMemoryActor(input.actor),
9
+ ].join('\u0001');
10
+ return `mem_${hash64Hex(payload)}`;
11
+ }
12
+ export function normalizeMemoryInput(input, provenance = {}) {
13
+ const kind = normalizeMemoryKind(input.kind);
14
+ if (!kind) {
15
+ throw new Error('Memory kind must be a non-empty string.');
16
+ }
17
+ const text = normalizeMemoryText(input.text);
18
+ if (!text) {
19
+ throw new Error('Memory text must be a non-empty string.');
20
+ }
21
+ const ts = normalizeMemoryTimestamp(input.ts ?? provenance.ts ?? 0);
22
+ const actor = normalizeMemoryActor(input.actor ?? provenance.actor ?? 'cortex');
23
+ const labels = validateMemoryLabels(input.labels);
24
+ const namespace = normalizeMemoryNamespace(input.namespace);
25
+ const source = normalizeMemorySource(input.source);
26
+ const importance = normalizeMemoryRatio(input.importance, 'importance');
27
+ const confidence = normalizeMemoryRatio(input.confidence, 'confidence');
28
+ return {
29
+ version: 1,
30
+ id: createMemoryId({ kind, text, ts, actor }),
31
+ kind,
32
+ text,
33
+ labels,
34
+ namespace,
35
+ source,
36
+ importance,
37
+ confidence,
38
+ ts,
39
+ actor,
40
+ links: [],
41
+ };
42
+ }
43
+ export function normalizeMemoryKind(kind) {
44
+ return normalize(String(kind ?? '')).replace(/\s+/g, ' ').trim();
45
+ }
46
+ export function normalizeMemoryText(text) {
47
+ return String(text ?? '').trim();
48
+ }
49
+ export function normalizeMemoryNamespace(namespace) {
50
+ const normalized = normalizeMemoryLabel(namespace ?? '');
51
+ return normalized || undefined;
52
+ }
53
+ export function normalizeMemorySource(source) {
54
+ const normalized = normalize(String(source ?? '')).replace(/\s+/g, ' ').trim();
55
+ return normalized || undefined;
56
+ }
57
+ export function normalizeMemoryActor(actor) {
58
+ return String(actor ?? '').replace(/\s+/g, ' ').trim();
59
+ }
60
+ export function normalizeMemoryTimestamp(ts) {
61
+ const value = Number(ts);
62
+ if (!Number.isFinite(value)) {
63
+ throw new Error('Memory timestamp must be a finite number.');
64
+ }
65
+ return value;
66
+ }
67
+ function normalizeMemoryRatio(value, name) {
68
+ if (value === undefined || value === null)
69
+ return undefined;
70
+ if (!Number.isFinite(value)) {
71
+ throw new Error(`Memory ${name} must be a finite number.`);
72
+ }
73
+ if (value < 0)
74
+ return 0;
75
+ if (value > 1)
76
+ return 1;
77
+ return value;
78
+ }
79
+ function normalizeMemoryTextForId(text) {
80
+ return normalize(String(text ?? '')).replace(/\s+/g, ' ').trim();
81
+ }
82
+ function hash64Hex(input) {
83
+ let hash = 0xcbf29ce484222325n;
84
+ const prime = 0x100000001b3n;
85
+ for (const char of input) {
86
+ hash ^= BigInt(char.codePointAt(0) ?? 0);
87
+ hash = (hash * prime) & 0xffffffffffffffffn;
88
+ }
89
+ return hash.toString(16).padStart(16, '0');
90
+ }
@@ -0,0 +1,3 @@
1
+ import type { ClaimOp } from '../graph/log.js';
2
+ import type { MemoryEngramV1 } from './engram.js';
3
+ export declare function memoryToClaimOps(memory: MemoryEngramV1): ClaimOp[];
@@ -0,0 +1,65 @@
1
+ import { computeEdgeId, computeNodeId, normalizeClaimLabel } from '../graph/claim_graph.js';
2
+ import { validateMemoryLabels } from './label.js';
3
+ export function memoryToClaimOps(memory) {
4
+ const nodeOps = new Map();
5
+ const edgeOps = new Map();
6
+ const memoryLabel = memoryNodeLabel(memory.id);
7
+ upsertNode(nodeOps, memoryLabel, memory.ts, memory.actor);
8
+ for (const label of validateMemoryLabels(memory.labels)) {
9
+ const entityLabel = normalizeClaimLabel(label);
10
+ if (!entityLabel)
11
+ continue;
12
+ upsertNode(nodeOps, entityLabel, memory.ts, memory.actor);
13
+ upsertEdge(edgeOps, memoryLabel, 'mentions', entityLabel, memory.ts, memory.actor);
14
+ }
15
+ for (const link of sortedLinks(memory.links)) {
16
+ const relation = normalizeClaimLabel(link.relation);
17
+ if (!relation)
18
+ continue;
19
+ const targetLabel = memoryNodeLabel(link.to);
20
+ upsertNode(nodeOps, targetLabel, link.ts, link.actor);
21
+ upsertEdge(edgeOps, memoryLabel, relation, targetLabel, link.ts, link.actor);
22
+ }
23
+ return [...nodeOps.values(), ...edgeOps.values()];
24
+ }
25
+ function memoryNodeLabel(id) {
26
+ return normalizeClaimLabel(`memory ${id}`);
27
+ }
28
+ function upsertNode(nodeOps, label, ts, actor) {
29
+ if (!label)
30
+ return;
31
+ const id = computeNodeId(label);
32
+ if (nodeOps.has(id))
33
+ return;
34
+ nodeOps.set(id, {
35
+ op: 'upsert_node',
36
+ id,
37
+ label,
38
+ ts,
39
+ actor,
40
+ });
41
+ }
42
+ function upsertEdge(edgeOps, fromLabel, relation, toLabel, ts, actor) {
43
+ if (!fromLabel || !relation || !toLabel)
44
+ return;
45
+ const from = computeNodeId(fromLabel);
46
+ const to = computeNodeId(toLabel);
47
+ const id = computeEdgeId(from, relation, to);
48
+ if (edgeOps.has(id))
49
+ return;
50
+ edgeOps.set(id, {
51
+ op: 'add_edge',
52
+ from,
53
+ p: relation,
54
+ to,
55
+ ts,
56
+ actor,
57
+ });
58
+ }
59
+ function sortedLinks(memoryLinks) {
60
+ return [...memoryLinks].sort((a, b) => a.ts - b.ts ||
61
+ a.actor.localeCompare(b.actor) ||
62
+ a.relation.localeCompare(b.relation) ||
63
+ a.to.localeCompare(b.to) ||
64
+ a.id.localeCompare(b.id));
65
+ }
@@ -0,0 +1,13 @@
1
+ export { normalizeMemoryLabel, validateMemoryLabels, matchesMemoryLabels, normalizeMemoryLabelTokens, } from './label.js';
2
+ export type { MemoryKind, MemoryLinkV1, MemoryLinkV1 as MemoryLink, MemoryEngramV1, MemoryEngramV1 as MemoryEngram, MemoryInputV1, MemoryInputV1 as MemoryInput, MemoryProvenanceV1, MemoryProvenanceV1 as MemoryProvenance, } from './engram.js';
3
+ export { createMemoryId, normalizeMemoryInput, normalizeMemoryKind, normalizeMemoryText, normalizeMemoryNamespace, normalizeMemorySource, normalizeMemoryActor, normalizeMemoryTimestamp, } from './engram.js';
4
+ export type { MemoryLogV1, MemoryOpV1 } from './log.js';
5
+ export type { MemoryLogV1 as MemoryLog, MemoryOpV1 as MemoryOp, } from './log.js';
6
+ export { createMemoryLog, appendMemoryOp, mergeMemoryLogs, serializeMemoryLog, deserializeMemoryLog, applyMemoryLog, } from './log.js';
7
+ export type { CortexV1, CortexV1 as Cortex, CortexWriteResult, } from './cortex.js';
8
+ export { createCortex, remember, forget, labelMemory, linkMemories } from './cortex.js';
9
+ export type { RecallOptionsV1, RecallOptionsV1 as RecallOptions, MemoryRecallHitV1, MemoryRecallHitV1 as MemoryRecallHit, } from './recall.js';
10
+ export { recall } from './recall.js';
11
+ export type { ConsolidateMemoriesOptionsV1, ConsolidateMemoriesOptionsV1 as ConsolidateMemoriesOptions, } from './consolidate.js';
12
+ export { consolidateMemories } from './consolidate.js';
13
+ export { memoryToClaimOps } from './graph_adapter.js';
@@ -0,0 +1,7 @@
1
+ export { normalizeMemoryLabel, validateMemoryLabels, matchesMemoryLabels, normalizeMemoryLabelTokens, } from './label.js';
2
+ export { createMemoryId, normalizeMemoryInput, normalizeMemoryKind, normalizeMemoryText, normalizeMemoryNamespace, normalizeMemorySource, normalizeMemoryActor, normalizeMemoryTimestamp, } from './engram.js';
3
+ export { createMemoryLog, appendMemoryOp, mergeMemoryLogs, serializeMemoryLog, deserializeMemoryLog, applyMemoryLog, } from './log.js';
4
+ export { createCortex, remember, forget, labelMemory, linkMemories } from './cortex.js';
5
+ export { recall } from './recall.js';
6
+ export { consolidateMemories } from './consolidate.js';
7
+ export { memoryToClaimOps } from './graph_adapter.js';
@@ -0,0 +1,4 @@
1
+ export declare function normalizeMemoryLabel(label: string): string;
2
+ export declare function validateMemoryLabels(labels?: string | readonly string[] | null): string[];
3
+ export declare function matchesMemoryLabels(memoryLabels?: string[] | string | null, requestedLabels?: string | readonly string[] | null): boolean;
4
+ export declare function normalizeMemoryLabelTokens(label: string): string[];