@mono-agent/memory 0.4.1
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 +61 -0
- package/dist/bujo/capture.d.ts +20 -0
- package/dist/bujo/capture.d.ts.map +1 -0
- package/dist/bujo/capture.js +77 -0
- package/dist/bujo/capture.js.map +1 -0
- package/dist/bujo/cli-env.d.ts +11 -0
- package/dist/bujo/cli-env.d.ts.map +1 -0
- package/dist/bujo/cli-env.js +30 -0
- package/dist/bujo/cli-env.js.map +1 -0
- package/dist/bujo/cli.d.ts +3 -0
- package/dist/bujo/cli.d.ts.map +1 -0
- package/dist/bujo/cli.js +98 -0
- package/dist/bujo/cli.js.map +1 -0
- package/dist/bujo/consolidate.d.ts +15 -0
- package/dist/bujo/consolidate.d.ts.map +1 -0
- package/dist/bujo/consolidate.js +61 -0
- package/dist/bujo/consolidate.js.map +1 -0
- package/dist/bujo/daily.d.ts +17 -0
- package/dist/bujo/daily.d.ts.map +1 -0
- package/dist/bujo/daily.js +47 -0
- package/dist/bujo/daily.js.map +1 -0
- package/dist/bujo/distill.d.ts +10 -0
- package/dist/bujo/distill.d.ts.map +1 -0
- package/dist/bujo/distill.js +50 -0
- package/dist/bujo/distill.js.map +1 -0
- package/dist/bujo/entities.d.ts +24 -0
- package/dist/bujo/entities.d.ts.map +1 -0
- package/dist/bujo/entities.js +80 -0
- package/dist/bujo/entities.js.map +1 -0
- package/dist/bujo/grammar.d.ts +18 -0
- package/dist/bujo/grammar.d.ts.map +1 -0
- package/dist/bujo/grammar.js +147 -0
- package/dist/bujo/grammar.js.map +1 -0
- package/dist/bujo/graph.d.ts +17 -0
- package/dist/bujo/graph.d.ts.map +1 -0
- package/dist/bujo/graph.js +96 -0
- package/dist/bujo/graph.js.map +1 -0
- package/dist/bujo/ids.d.ts +9 -0
- package/dist/bujo/ids.d.ts.map +1 -0
- package/dist/bujo/ids.js +23 -0
- package/dist/bujo/ids.js.map +1 -0
- package/dist/bujo/index.d.ts +26 -0
- package/dist/bujo/index.d.ts.map +1 -0
- package/dist/bujo/index.js +20 -0
- package/dist/bujo/index.js.map +1 -0
- package/dist/bujo/json.d.ts +3 -0
- package/dist/bujo/json.d.ts.map +1 -0
- package/dist/bujo/json.js +58 -0
- package/dist/bujo/json.js.map +1 -0
- package/dist/bujo/llm.d.ts +14 -0
- package/dist/bujo/llm.d.ts.map +1 -0
- package/dist/bujo/llm.js +2 -0
- package/dist/bujo/llm.js.map +1 -0
- package/dist/bujo/migrate.d.ts +12 -0
- package/dist/bujo/migrate.d.ts.map +1 -0
- package/dist/bujo/migrate.js +136 -0
- package/dist/bujo/migrate.js.map +1 -0
- package/dist/bujo/model-error.d.ts +16 -0
- package/dist/bujo/model-error.d.ts.map +1 -0
- package/dist/bujo/model-error.js +20 -0
- package/dist/bujo/model-error.js.map +1 -0
- package/dist/bujo/ollama-llm.d.ts +7 -0
- package/dist/bujo/ollama-llm.d.ts.map +1 -0
- package/dist/bujo/ollama-llm.js +43 -0
- package/dist/bujo/ollama-llm.js.map +1 -0
- package/dist/bujo/projections.d.ts +8 -0
- package/dist/bujo/projections.d.ts.map +1 -0
- package/dist/bujo/projections.js +53 -0
- package/dist/bujo/projections.js.map +1 -0
- package/dist/bujo/rebuild.d.ts +12 -0
- package/dist/bujo/rebuild.d.ts.map +1 -0
- package/dist/bujo/rebuild.js +73 -0
- package/dist/bujo/rebuild.js.map +1 -0
- package/dist/bujo/recall.d.ts +7 -0
- package/dist/bujo/recall.d.ts.map +1 -0
- package/dist/bujo/recall.js +33 -0
- package/dist/bujo/recall.js.map +1 -0
- package/dist/bujo/reconcile.d.ts +37 -0
- package/dist/bujo/reconcile.d.ts.map +1 -0
- package/dist/bujo/reconcile.js +190 -0
- package/dist/bujo/reconcile.js.map +1 -0
- package/dist/bujo/reflect.d.ts +30 -0
- package/dist/bujo/reflect.d.ts.map +1 -0
- package/dist/bujo/reflect.js +100 -0
- package/dist/bujo/reflect.js.map +1 -0
- package/dist/bujo/store.d.ts +77 -0
- package/dist/bujo/store.d.ts.map +1 -0
- package/dist/bujo/store.js +222 -0
- package/dist/bujo/store.js.map +1 -0
- package/dist/bujo/types.d.ts +39 -0
- package/dist/bujo/types.d.ts.map +1 -0
- package/dist/bujo/types.js +2 -0
- package/dist/bujo/types.js.map +1 -0
- package/dist/search/chunks.d.ts +14 -0
- package/dist/search/chunks.d.ts.map +1 -0
- package/dist/search/chunks.js +75 -0
- package/dist/search/chunks.js.map +1 -0
- package/dist/search/circuit-breaker.d.ts +34 -0
- package/dist/search/circuit-breaker.d.ts.map +1 -0
- package/dist/search/circuit-breaker.js +89 -0
- package/dist/search/circuit-breaker.js.map +1 -0
- package/dist/search/embeddings.d.ts +44 -0
- package/dist/search/embeddings.d.ts.map +1 -0
- package/dist/search/embeddings.js +141 -0
- package/dist/search/embeddings.js.map +1 -0
- package/dist/search/index.d.ts +8 -0
- package/dist/search/index.d.ts.map +1 -0
- package/dist/search/index.js +5 -0
- package/dist/search/index.js.map +1 -0
- package/dist/search/types.d.ts +41 -0
- package/dist/search/types.d.ts.map +1 -0
- package/dist/search/types.js +2 -0
- package/dist/search/types.js.map +1 -0
- package/dist/search/vector-index.d.ts +28 -0
- package/dist/search/vector-index.d.ts.map +1 -0
- package/dist/search/vector-index.js +214 -0
- package/dist/search/vector-index.js.map +1 -0
- package/dist/store/contract.d.ts +2 -0
- package/dist/store/contract.d.ts.map +1 -0
- package/dist/store/contract.js +2 -0
- package/dist/store/contract.js.map +1 -0
- package/dist/store/db.d.ts +84 -0
- package/dist/store/db.d.ts.map +1 -0
- package/dist/store/db.js +471 -0
- package/dist/store/db.js.map +1 -0
- package/dist/store/fts.d.ts +3 -0
- package/dist/store/fts.d.ts.map +1 -0
- package/dist/store/fts.js +6 -0
- package/dist/store/fts.js.map +1 -0
- package/dist/store/index.d.ts +5 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +3 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/ranking.d.ts +16 -0
- package/dist/store/ranking.d.ts.map +1 -0
- package/dist/store/ranking.js +32 -0
- package/dist/store/ranking.js.map +1 -0
- package/dist/store/schema.d.ts +3 -0
- package/dist/store/schema.d.ts.map +1 -0
- package/dist/store/schema.js +61 -0
- package/dist/store/schema.js.map +1 -0
- package/dist/store/types.d.ts +102 -0
- package/dist/store/types.d.ts.map +1 -0
- package/dist/store/types.js +25 -0
- package/dist/store/types.js.map +1 -0
- package/dist/store/vec.d.ts +12 -0
- package/dist/store/vec.d.ts.map +1 -0
- package/dist/store/vec.js +20 -0
- package/dist/store/vec.js.map +1 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# @mono-agent/memory
|
|
2
|
+
|
|
3
|
+
## Category
|
|
4
|
+
|
|
5
|
+
Category: `context`
|
|
6
|
+
|
|
7
|
+
## Responsibility
|
|
8
|
+
|
|
9
|
+
Local memory building blocks published as one package with explicit subpaths. `@mono-agent/memory/store` owns the SQLite substrate, schema, FTS5/sqlite-vec hybrid recall, and rebuildable record database. `@mono-agent/memory/search` owns embedding providers, circuit-breaking, chunk gathering, and the in-memory cosine vector index. `@mono-agent/memory/bujo` owns the Bullet-Journal memory engine: markdown grammar, canonical daily files, tier-aware capture/recall, entity graph projection, reflection, migration, and the `memory-bujo` maintenance CLI.
|
|
10
|
+
|
|
11
|
+
The shared `MemoryBlock`, `MemoryStore`, and `MemoryWriteResult` contracts live in `@mono-agent/agent-contracts`. The store subpath re-exports them for local-store consumers, but `@mono-agent/agent-contracts` is the source of truth.
|
|
12
|
+
|
|
13
|
+
## Install / Usage
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
pnpm --filter @mono-agent/memory run build
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { createBujoMemoryStore } from "@mono-agent/memory/bujo";
|
|
21
|
+
import { createEmbeddingProvider } from "@mono-agent/memory/search";
|
|
22
|
+
import { openMemoryDb } from "@mono-agent/memory/store";
|
|
23
|
+
import type { MemoryStore } from "@mono-agent/agent-contracts";
|
|
24
|
+
|
|
25
|
+
const embeddings = createEmbeddingProvider({ provider: "ollama", model: "nomic-embed-text:v1.5" });
|
|
26
|
+
const store: MemoryStore = createBujoMemoryStore({
|
|
27
|
+
root: "./memory",
|
|
28
|
+
embeddings,
|
|
29
|
+
dim: 768,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
await store.appendHostSummary("conv-1", "User prefers concise answers.");
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
memory-bujo rebuild ./memory
|
|
37
|
+
memory-bujo recall ./memory "what did we decide about releases?"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Public API
|
|
41
|
+
|
|
42
|
+
- `@mono-agent/memory/store`: `openMemoryDb`, `MemoryDb`, `DEFAULT_VEC_DIM`, `MEMORY_TYPES`, `MEMORY_STATUSES`, local record/entity/recall/stats types, and re-exported `MemoryBlock`, `MemoryStore`, `MemoryWriteResult`
|
|
43
|
+
- `@mono-agent/memory/search`: `createEmbeddingProvider`, `createCircuitBreakerEmbeddingProvider`, `createVectorMemoryIndex`, `gatherMemoryChunks`, embedding/search provider classes and types
|
|
44
|
+
- `@mono-agent/memory/bujo`: `createBujoMemoryStore`, `BujoMemoryStore`, `composeRecallBlock`, markdown grammar helpers, daily-file helpers, capture/reconcile/reflection/migration helpers, `createOllamaLlm`, and related BuJo/LLM types
|
|
45
|
+
- CLI: `memory-bujo`
|
|
46
|
+
|
|
47
|
+
## Dependency Boundary
|
|
48
|
+
|
|
49
|
+
This package may depend on core contracts and local persistence/search dependencies (`better-sqlite3`, `sqlite-vec`). It does not depend on hosts, harnesses, communication adapters, observability, provider runtimes, or external memory services. Internal subpaths use relative imports so the package has no package-to-self workspace dependency.
|
|
50
|
+
|
|
51
|
+
## What This Package Does Not Own
|
|
52
|
+
|
|
53
|
+
It does not own host configuration, backend selection, automatic `memory_recall` MCP wiring, external Supermemory storage, model runtime execution, communication channels, or run artifact persistence. `@mono-agent/agent-app` chooses which memory backend to build and wires the recall tool, while `@mono-agent/memory-supermemory` owns the external Supermemory backend.
|
|
54
|
+
|
|
55
|
+
## Verification
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pnpm --filter @mono-agent/memory run build
|
|
59
|
+
pnpm --filter @mono-agent/memory run typecheck
|
|
60
|
+
pnpm --filter @mono-agent/memory run test
|
|
61
|
+
```
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type ReconcileAction, type ReconcileDeps } from "./reconcile.js";
|
|
2
|
+
export interface CaptureTurnResult {
|
|
3
|
+
readonly actions: ReconcileAction[];
|
|
4
|
+
readonly entities: number;
|
|
5
|
+
readonly relations: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Full capture pipeline for a single conversation turn:
|
|
9
|
+
* 1. distill(text) → candidate memories
|
|
10
|
+
* 2. reconcile(candidates) → ADD / UPDATE / SUPERSEDE / NOOP actions (writes markdown + index)
|
|
11
|
+
* 3. extractEntities(text) → typed entities + relations
|
|
12
|
+
* 4. Persist each entity canonical-first: graph.jsonl, THEN mirror to the db index
|
|
13
|
+
* 5. Persist each relation canonical-first: graph.jsonl, THEN mirror to the db index
|
|
14
|
+
* 6. Link this turn's ADDed memories to extracted entities via `about` edges (coarse co-occurrence)
|
|
15
|
+
*
|
|
16
|
+
* Never throws on a single bad entity/relation item — each write is wrapped defensively.
|
|
17
|
+
* Returns a summary: actions list, entity count, relation count.
|
|
18
|
+
*/
|
|
19
|
+
export declare function captureTurn(text: string, deps: ReconcileDeps): Promise<CaptureTurnResult>;
|
|
20
|
+
//# sourceMappingURL=capture.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/bujo/capture.ts"],"names":[],"mappings":"AAGA,OAAO,EAAa,KAAK,eAAe,EAAE,KAAK,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAErF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,eAAe,EAAE,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA8D/F"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { distill } from "./distill.js";
|
|
2
|
+
import { extractEntities } from "./entities.js";
|
|
3
|
+
import { appendEntity, appendRelation } from "./graph.js";
|
|
4
|
+
import { reconcile } from "./reconcile.js";
|
|
5
|
+
/**
|
|
6
|
+
* Full capture pipeline for a single conversation turn:
|
|
7
|
+
* 1. distill(text) → candidate memories
|
|
8
|
+
* 2. reconcile(candidates) → ADD / UPDATE / SUPERSEDE / NOOP actions (writes markdown + index)
|
|
9
|
+
* 3. extractEntities(text) → typed entities + relations
|
|
10
|
+
* 4. Persist each entity canonical-first: graph.jsonl, THEN mirror to the db index
|
|
11
|
+
* 5. Persist each relation canonical-first: graph.jsonl, THEN mirror to the db index
|
|
12
|
+
* 6. Link this turn's ADDed memories to extracted entities via `about` edges (coarse co-occurrence)
|
|
13
|
+
*
|
|
14
|
+
* Never throws on a single bad entity/relation item — each write is wrapped defensively.
|
|
15
|
+
* Returns a summary: actions list, entity count, relation count.
|
|
16
|
+
*/
|
|
17
|
+
export async function captureTurn(text, deps) {
|
|
18
|
+
// Step 1+2: distill candidates and reconcile against existing index
|
|
19
|
+
const candidates = await distill(text, deps.llm);
|
|
20
|
+
const actions = await reconcile(candidates, deps);
|
|
21
|
+
// Step 3: extract entities and relations from the turn text
|
|
22
|
+
const extraction = await extractEntities(text, deps.llm);
|
|
23
|
+
const now = deps.now();
|
|
24
|
+
const createdAt = now.toISOString();
|
|
25
|
+
// Step 4: persist each entity canonical-first (graph.jsonl), then mirror to the rebuildable db
|
|
26
|
+
// index. graph.jsonl is the canonical source rebuildFromMarkdown reads; writing it first means a
|
|
27
|
+
// crash between the two writes still recovers the entity on the next rebuild.
|
|
28
|
+
for (const entity of extraction.entities) {
|
|
29
|
+
try {
|
|
30
|
+
const record = {
|
|
31
|
+
id: entity.id,
|
|
32
|
+
name: entity.name,
|
|
33
|
+
...(entity.type !== undefined ? { type: entity.type } : {}),
|
|
34
|
+
createdAt,
|
|
35
|
+
};
|
|
36
|
+
appendEntity(deps.root, record);
|
|
37
|
+
deps.db.upsertEntity(record);
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// Per-item isolation: a single bad entity must not abort the turn
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Step 5: persist each relation canonical-first (graph.jsonl), then mirror to the db index.
|
|
44
|
+
for (const relation of extraction.relations) {
|
|
45
|
+
try {
|
|
46
|
+
appendRelation(deps.root, {
|
|
47
|
+
src: relation.src,
|
|
48
|
+
dst: relation.dst,
|
|
49
|
+
relation: relation.relation,
|
|
50
|
+
createdAt,
|
|
51
|
+
});
|
|
52
|
+
deps.db.addEntityRelation(relation.src, relation.dst, relation.relation);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// Per-item isolation: a single bad relation must not abort the turn
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Step 6: link ADDed memories to extracted entities via `about` edges
|
|
59
|
+
const addedIds = actions.flatMap((a) => (a.kind === "add" ? [a.id] : []));
|
|
60
|
+
const entityIds = extraction.entities.map((e) => e.id);
|
|
61
|
+
for (const memoryId of addedIds) {
|
|
62
|
+
for (const entityId of entityIds) {
|
|
63
|
+
try {
|
|
64
|
+
deps.db.addEdge(memoryId, entityId, "about");
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
// Per-item isolation
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
actions,
|
|
73
|
+
entities: extraction.entities.length,
|
|
74
|
+
relations: extraction.relations.length,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=capture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/bujo/capture.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { EmbeddingProvider } from "../search/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the embeddings provider from the same `MONO_AGENT_MEMORY_EMBEDDINGS_*` env vars the agent
|
|
4
|
+
* and the MCP server use. Returns undefined when no provider is configured — embeddings are opt-in,
|
|
5
|
+
* so lite-tier (FTS-only) recall/rebuild works without any embedding service (e.g. no Ollama running).
|
|
6
|
+
*/
|
|
7
|
+
export declare function readEmbeddings(env?: NodeJS.ProcessEnv): {
|
|
8
|
+
provider: EmbeddingProvider;
|
|
9
|
+
dim: number;
|
|
10
|
+
} | undefined;
|
|
11
|
+
//# sourceMappingURL=cli-env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-env.d.ts","sourceRoot":"","sources":["../../src/bujo/cli-env.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE5D;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC;IAAE,QAAQ,EAAE,iBAAiB,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAqB1D"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { createEmbeddingProvider } from "../search/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the embeddings provider from the same `MONO_AGENT_MEMORY_EMBEDDINGS_*` env vars the agent
|
|
4
|
+
* and the MCP server use. Returns undefined when no provider is configured — embeddings are opt-in,
|
|
5
|
+
* so lite-tier (FTS-only) recall/rebuild works without any embedding service (e.g. no Ollama running).
|
|
6
|
+
*/
|
|
7
|
+
export function readEmbeddings(env = process.env) {
|
|
8
|
+
const providerKind = env.MONO_AGENT_MEMORY_EMBEDDINGS_PROVIDER?.trim();
|
|
9
|
+
if (!providerKind)
|
|
10
|
+
return undefined;
|
|
11
|
+
if (providerKind !== "ollama" && providerKind !== "openai") {
|
|
12
|
+
throw new Error(`unsupported MONO_AGENT_MEMORY_EMBEDDINGS_PROVIDER "${providerKind}" (expected "ollama" or "openai")`);
|
|
13
|
+
}
|
|
14
|
+
const model = env.MONO_AGENT_MEMORY_EMBEDDINGS_MODEL?.trim() || "nomic-embed-text:v1.5";
|
|
15
|
+
const endpoint = env.MONO_AGENT_MEMORY_EMBEDDINGS_ENDPOINT?.trim();
|
|
16
|
+
const apiKey = env.MONO_AGENT_MEMORY_EMBEDDINGS_API_KEY?.trim();
|
|
17
|
+
const dimStr = env.MONO_AGENT_MEMORY_EMBEDDINGS_DIM?.trim();
|
|
18
|
+
const dim = dimStr ? Number(dimStr) : 768;
|
|
19
|
+
if (!Number.isInteger(dim) || dim <= 0) {
|
|
20
|
+
throw new Error(`invalid MONO_AGENT_MEMORY_EMBEDDINGS_DIM "${dimStr ?? ""}" (expected a positive integer)`);
|
|
21
|
+
}
|
|
22
|
+
const provider = createEmbeddingProvider({
|
|
23
|
+
provider: providerKind,
|
|
24
|
+
model,
|
|
25
|
+
...(endpoint ? { endpoint } : {}),
|
|
26
|
+
...(apiKey ? { apiKey } : {}),
|
|
27
|
+
});
|
|
28
|
+
return { provider, dim };
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=cli-env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli-env.js","sourceRoot":"","sources":["../../src/bujo/cli-env.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAG7D;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAC5B,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,YAAY,GAAG,GAAG,CAAC,qCAAqC,EAAE,IAAI,EAAE,CAAC;IACvE,IAAI,CAAC,YAAY;QAAE,OAAO,SAAS,CAAC;IACpC,IAAI,YAAY,KAAK,QAAQ,IAAI,YAAY,KAAK,QAAQ,EAAE,CAAC;QAC3D,MAAM,IAAI,KAAK,CAAC,sDAAsD,YAAY,mCAAmC,CAAC,CAAC;IACzH,CAAC;IACD,MAAM,KAAK,GAAG,GAAG,CAAC,kCAAkC,EAAE,IAAI,EAAE,IAAI,uBAAuB,CAAC;IACxF,MAAM,QAAQ,GAAG,GAAG,CAAC,qCAAqC,EAAE,IAAI,EAAE,CAAC;IACnE,MAAM,MAAM,GAAG,GAAG,CAAC,oCAAoC,EAAE,IAAI,EAAE,CAAC;IAChE,MAAM,MAAM,GAAG,GAAG,CAAC,gCAAgC,EAAE,IAAI,EAAE,CAAC;IAC5D,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAC1C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,6CAA6C,MAAM,IAAI,EAAE,iCAAiC,CAAC,CAAC;IAC9G,CAAC;IACD,MAAM,QAAQ,GAAG,uBAAuB,CAAC;QACvC,QAAQ,EAAE,YAAY;QACtB,KAAK;QACL,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACjC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9B,CAAC,CAAC;IACH,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/bujo/cli.ts"],"names":[],"mappings":""}
|
package/dist/bujo/cli.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { openMemoryDb } from "../store/index.js";
|
|
4
|
+
import { readEmbeddings } from "./cli-env.js";
|
|
5
|
+
import { createIdFactory } from "./ids.js";
|
|
6
|
+
import { migrate } from "./migrate.js";
|
|
7
|
+
import { createOllamaLlm } from "./ollama-llm.js";
|
|
8
|
+
import { writeFutureLog, writeIndex } from "./projections.js";
|
|
9
|
+
import { rebuildFromMarkdown } from "./rebuild.js";
|
|
10
|
+
import { reflect } from "./reflect.js";
|
|
11
|
+
/** Optional per-call LLM timeout override (ms). Invalid values fall back to the client default. */
|
|
12
|
+
function llmTimeoutMsFromEnv() {
|
|
13
|
+
const raw = process.env.MONO_AGENT_MEMORY_LLM_TIMEOUT_MS?.trim();
|
|
14
|
+
if (!raw)
|
|
15
|
+
return undefined;
|
|
16
|
+
const parsed = Number(raw);
|
|
17
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;
|
|
18
|
+
}
|
|
19
|
+
async function main() {
|
|
20
|
+
const [command, root, ...rest] = process.argv.slice(2);
|
|
21
|
+
if (command !== "rebuild" && command !== "recall" && command !== "index" && command !== "reflect" && command !== "migrate") {
|
|
22
|
+
process.stderr.write("usage: memory-bujo <rebuild|recall|index|reflect|migrate> <root> [query]\n");
|
|
23
|
+
process.exit(2);
|
|
24
|
+
}
|
|
25
|
+
if (root === undefined) {
|
|
26
|
+
process.stderr.write("error: <root> is required\n");
|
|
27
|
+
process.exit(2);
|
|
28
|
+
}
|
|
29
|
+
const query = rest.join(" ").trim();
|
|
30
|
+
if (command === "recall" && query.length === 0) {
|
|
31
|
+
process.stderr.write("error: recall requires a non-empty <query>\n");
|
|
32
|
+
process.exit(2);
|
|
33
|
+
}
|
|
34
|
+
if (command === "reflect" || command === "migrate") {
|
|
35
|
+
const chatModel = process.env.MONO_AGENT_MEMORY_LLM_MODEL;
|
|
36
|
+
if (chatModel === undefined) {
|
|
37
|
+
process.stderr.write("error: set MONO_AGENT_MEMORY_LLM_MODEL to a local Ollama chat model (e.g. qwen3.6:latest)\n");
|
|
38
|
+
process.exit(2);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Embeddings are opt-in (matching the agent/MCP): only enabled when an embeddings provider is
|
|
42
|
+
// configured. A lite-tier (FTS-only) recall/rebuild then needs no embedding service running.
|
|
43
|
+
const embeddingsConfig = readEmbeddings();
|
|
44
|
+
const db = openMemoryDb({
|
|
45
|
+
path: join(root, "memory.db"),
|
|
46
|
+
...(embeddingsConfig !== undefined ? { embeddings: embeddingsConfig.provider, dim: embeddingsConfig.dim } : {}),
|
|
47
|
+
});
|
|
48
|
+
try {
|
|
49
|
+
if (command === "rebuild") {
|
|
50
|
+
const result = await rebuildFromMarkdown(root, db);
|
|
51
|
+
process.stdout.write(`rebuilt: indexed ${result.indexed} memories into ${join(root, "memory.db")}\n`);
|
|
52
|
+
}
|
|
53
|
+
else if (command === "index") {
|
|
54
|
+
writeIndex(root, db, new Date());
|
|
55
|
+
process.stdout.write(`wrote ${join(root, "index.md")}\n`);
|
|
56
|
+
}
|
|
57
|
+
else if (command === "reflect") {
|
|
58
|
+
// MONO_AGENT_MEMORY_LLM_MODEL is guaranteed non-undefined here (guard above)
|
|
59
|
+
const chatModel = process.env.MONO_AGENT_MEMORY_LLM_MODEL;
|
|
60
|
+
const timeoutMs = llmTimeoutMsFromEnv();
|
|
61
|
+
const llm = createOllamaLlm({
|
|
62
|
+
model: chatModel,
|
|
63
|
+
...(process.env.MONO_AGENT_MEMORY_LLM_ENDPOINT ? { endpoint: process.env.MONO_AGENT_MEMORY_LLM_ENDPOINT } : {}),
|
|
64
|
+
...(timeoutMs !== undefined ? { timeoutMs } : {}),
|
|
65
|
+
});
|
|
66
|
+
const r = await reflect({ db, root, llm, nextId: createIdFactory(), now: () => new Date() });
|
|
67
|
+
writeFutureLog(root, db, new Date());
|
|
68
|
+
writeIndex(root, db, new Date());
|
|
69
|
+
process.stdout.write(`reflected: decayed ${r.decayed}, insights ${r.insights}, due ${r.due}\n`);
|
|
70
|
+
}
|
|
71
|
+
else if (command === "migrate") {
|
|
72
|
+
// MONO_AGENT_MEMORY_LLM_MODEL is guaranteed non-undefined here (guard above)
|
|
73
|
+
const chatModel = process.env.MONO_AGENT_MEMORY_LLM_MODEL;
|
|
74
|
+
const timeoutMs = llmTimeoutMsFromEnv();
|
|
75
|
+
const llm = createOllamaLlm({
|
|
76
|
+
model: chatModel,
|
|
77
|
+
...(process.env.MONO_AGENT_MEMORY_LLM_ENDPOINT ? { endpoint: process.env.MONO_AGENT_MEMORY_LLM_ENDPOINT } : {}),
|
|
78
|
+
...(timeoutMs !== undefined ? { timeoutMs } : {}),
|
|
79
|
+
});
|
|
80
|
+
const m = await migrate({ db, root, llm, nextId: createIdFactory(), now: () => new Date() });
|
|
81
|
+
writeFutureLog(root, db, new Date());
|
|
82
|
+
process.stdout.write(`migrated: promoted ${m.promoted}, rescheduled ${m.rescheduled}, clustered ${m.clustered}, forgotten ${m.forgotten}, reviewed ${m.reviewed}\n`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
const hits = await db.recall(query, { topK: 8 });
|
|
86
|
+
for (const hit of hits)
|
|
87
|
+
process.stdout.write(`${hit.score.toFixed(3)} ${hit.record.text}\n`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
finally {
|
|
91
|
+
db.close();
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
main().catch((error) => {
|
|
95
|
+
process.stderr.write(`memory-bujo failed: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
});
|
|
98
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../src/bujo/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { MemoryDb } from "../store/index.js";
|
|
2
|
+
export interface ConsolidateDeps {
|
|
3
|
+
readonly root: string;
|
|
4
|
+
readonly db: MemoryDb;
|
|
5
|
+
readonly now: Date;
|
|
6
|
+
}
|
|
7
|
+
export interface ConsolidateResult {
|
|
8
|
+
readonly decayed: number;
|
|
9
|
+
readonly duplicateGroups: number;
|
|
10
|
+
readonly superseded: number;
|
|
11
|
+
readonly markdownInvalidated: number;
|
|
12
|
+
}
|
|
13
|
+
/** Deterministic, no-LLM maintenance: decay, exact-normalized duplicate folding, projections. */
|
|
14
|
+
export declare function consolidateBujoMemory(deps: ConsolidateDeps): Promise<ConsolidateResult>;
|
|
15
|
+
//# sourceMappingURL=consolidate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consolidate.d.ts","sourceRoot":"","sources":["../../src/bujo/consolidate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAgB,MAAM,mBAAmB,CAAC;AAKhE,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,IAAI,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;CACtC;AAED,iGAAiG;AACjG,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA0B7F"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { rewriteBullet } from "./daily.js";
|
|
2
|
+
import { writeEmptyFutureLog, writeIndex } from "./projections.js";
|
|
3
|
+
/** Deterministic, no-LLM maintenance: decay, exact-normalized duplicate folding, projections. */
|
|
4
|
+
export async function consolidateBujoMemory(deps) {
|
|
5
|
+
const { decayed } = deps.db.applyDecay(deps.now);
|
|
6
|
+
const liveRecords = deps.db.topSalient(Math.max(deps.db.count(), 1));
|
|
7
|
+
const groups = groupByNormalizedText(liveRecords);
|
|
8
|
+
let duplicateGroups = 0;
|
|
9
|
+
let superseded = 0;
|
|
10
|
+
let markdownInvalidated = 0;
|
|
11
|
+
for (const group of groups.values()) {
|
|
12
|
+
if (group.length < 2)
|
|
13
|
+
continue;
|
|
14
|
+
duplicateGroups += 1;
|
|
15
|
+
const [keeper, ...duplicates] = [...group].sort(compareNewestFirst);
|
|
16
|
+
if (keeper === undefined)
|
|
17
|
+
continue;
|
|
18
|
+
for (const duplicate of duplicates) {
|
|
19
|
+
deps.db.markSuperseded(duplicate.id, keeper.id, deps.now.toISOString());
|
|
20
|
+
superseded += 1;
|
|
21
|
+
if (duplicate.source.file !== undefined) {
|
|
22
|
+
const rewritten = rewriteBullet(deps.root, duplicate.source.file, duplicate.id, { status: "invalidated" });
|
|
23
|
+
if (rewritten)
|
|
24
|
+
markdownInvalidated += 1;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
writeIndex(deps.root, deps.db, deps.now);
|
|
29
|
+
writeEmptyFutureLog(deps.root);
|
|
30
|
+
return { decayed, duplicateGroups, superseded, markdownInvalidated };
|
|
31
|
+
}
|
|
32
|
+
function groupByNormalizedText(records) {
|
|
33
|
+
const groups = new Map();
|
|
34
|
+
for (const record of records) {
|
|
35
|
+
const key = normalizeFactText(record.text);
|
|
36
|
+
if (key.length === 0)
|
|
37
|
+
continue;
|
|
38
|
+
const existing = groups.get(key);
|
|
39
|
+
if (existing === undefined) {
|
|
40
|
+
groups.set(key, [record]);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
existing.push(record);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return groups;
|
|
47
|
+
}
|
|
48
|
+
function normalizeFactText(text) {
|
|
49
|
+
return text
|
|
50
|
+
.normalize("NFKC")
|
|
51
|
+
.toLocaleLowerCase("en-US")
|
|
52
|
+
.replace(/[^\p{Letter}\p{Number}]+/gu, " ")
|
|
53
|
+
.trim();
|
|
54
|
+
}
|
|
55
|
+
function compareNewestFirst(a, b) {
|
|
56
|
+
const byCreated = Date.parse(b.createdAt) - Date.parse(a.createdAt);
|
|
57
|
+
if (byCreated !== 0)
|
|
58
|
+
return byCreated;
|
|
59
|
+
return b.id.localeCompare(a.id);
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=consolidate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"consolidate.js","sourceRoot":"","sources":["../../src/bujo/consolidate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Bullet } from "./types.js";
|
|
2
|
+
export declare function dailyFilePath(root: string, when: Date): string;
|
|
3
|
+
/** Append a bullet to today's daily file (creating it with a heading if absent). Returns the bullet. */
|
|
4
|
+
export declare function appendBullet(root: string, bullet: Bullet, when: Date): Bullet;
|
|
5
|
+
/**
|
|
6
|
+
* Rewrite a single bullet inside an existing daily file.
|
|
7
|
+
*
|
|
8
|
+
* Reads `<root>/<file>`, parses it, finds the line whose `bullet.id === id`,
|
|
9
|
+
* applies `patch` onto that Bullet (object spread), serializes and writes back.
|
|
10
|
+
*
|
|
11
|
+
* Returns `true` if the bullet was found and the file was rewritten, `false` if
|
|
12
|
+
* no bullet with `id` was found (file is not modified in that case).
|
|
13
|
+
*
|
|
14
|
+
* Non-bullet lines (prose, headings, blank lines) are preserved verbatim.
|
|
15
|
+
*/
|
|
16
|
+
export declare function rewriteBullet(root: string, file: string, id: string, patch: Partial<Pick<Bullet, "text" | "status" | "salience" | "isInsight" | "dueAt" | "refs">>): boolean;
|
|
17
|
+
//# sourceMappingURL=daily.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daily.d.ts","sourceRoot":"","sources":["../../src/bujo/daily.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CAG9D;AAED,wGAAwG;AACxG,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CAO7E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,WAAW,GAAG,OAAO,GAAG,MAAM,CAAC,CAAC,GAC5F,OAAO,CAmBT"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { parseDailyFile, serializeBullet, serializeDailyFile } from "./grammar.js";
|
|
4
|
+
export function dailyFilePath(root, when) {
|
|
5
|
+
const day = when.toISOString().slice(0, 10);
|
|
6
|
+
return join(root, "daily", `${day}.md`);
|
|
7
|
+
}
|
|
8
|
+
/** Append a bullet to today's daily file (creating it with a heading if absent). Returns the bullet. */
|
|
9
|
+
export function appendBullet(root, bullet, when) {
|
|
10
|
+
const path = dailyFilePath(root, when);
|
|
11
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
12
|
+
// existsSync (not read-and-catch) so a permission/IO error surfaces instead of being mistaken for a new file.
|
|
13
|
+
const header = existsSync(path) ? "" : `# ${when.toISOString().slice(0, 10)}\n\n`;
|
|
14
|
+
appendFileSync(path, `${header}${serializeBullet(bullet)}\n`, "utf8");
|
|
15
|
+
return bullet;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Rewrite a single bullet inside an existing daily file.
|
|
19
|
+
*
|
|
20
|
+
* Reads `<root>/<file>`, parses it, finds the line whose `bullet.id === id`,
|
|
21
|
+
* applies `patch` onto that Bullet (object spread), serializes and writes back.
|
|
22
|
+
*
|
|
23
|
+
* Returns `true` if the bullet was found and the file was rewritten, `false` if
|
|
24
|
+
* no bullet with `id` was found (file is not modified in that case).
|
|
25
|
+
*
|
|
26
|
+
* Non-bullet lines (prose, headings, blank lines) are preserved verbatim.
|
|
27
|
+
*/
|
|
28
|
+
export function rewriteBullet(root, file, id, patch) {
|
|
29
|
+
const path = join(root, file);
|
|
30
|
+
const content = readFileSync(path, "utf8");
|
|
31
|
+
const parsed = parseDailyFile(content);
|
|
32
|
+
let found = false;
|
|
33
|
+
const newLines = parsed.lines.map((line) => {
|
|
34
|
+
if (line.bullet === undefined || line.bullet.id !== id)
|
|
35
|
+
return line;
|
|
36
|
+
found = true;
|
|
37
|
+
// Build the merged bullet by applying only the defined patch keys so that
|
|
38
|
+
// exactOptionalPropertyTypes is satisfied (no undefined values injected).
|
|
39
|
+
const merged = { ...line.bullet, ...patch };
|
|
40
|
+
return { raw: line.raw, lineNumber: line.lineNumber, bullet: merged };
|
|
41
|
+
});
|
|
42
|
+
if (!found)
|
|
43
|
+
return false;
|
|
44
|
+
writeFileSync(path, serializeDailyFile({ lines: newLines }), "utf8");
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=daily.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daily.js","sourceRoot":"","sources":["../../src/bujo/daily.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7F,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGnF,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,IAAU;IACpD,MAAM,GAAG,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5C,OAAO,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,GAAG,KAAK,CAAC,CAAC;AAC1C,CAAC;AAED,wGAAwG;AACxG,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,MAAc,EAAE,IAAU;IACnE,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACvC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,8GAA8G;IAC9G,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC;IAClF,cAAc,CAAC,IAAI,EAAE,GAAG,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACtE,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAY,EACZ,IAAY,EACZ,EAAU,EACV,KAA6F;IAE7F,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9B,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;IAEvC,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACzC,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE;YAAE,OAAO,IAAI,CAAC;QACpE,KAAK,GAAG,IAAI,CAAC;QACb,0EAA0E;QAC1E,0EAA0E;QAC1E,MAAM,MAAM,GAAW,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,EAAE,CAAC;QACpD,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAEzB,aAAa,CAAC,IAAI,EAAE,kBAAkB,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;IACrE,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { MemoryType } from "../store/index.js";
|
|
2
|
+
import type { LlmComplete } from "./llm.js";
|
|
3
|
+
export interface CandidateMemory {
|
|
4
|
+
readonly type: MemoryType;
|
|
5
|
+
readonly text: string;
|
|
6
|
+
readonly salience: number;
|
|
7
|
+
readonly isInsight: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare function distill(text: string, llm: LlmComplete): Promise<CandidateMemory[]>;
|
|
10
|
+
//# sourceMappingURL=distill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"distill.d.ts","sourceRoot":"","sources":["../../src/bujo/distill.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAI5C,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AASD,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAaxF"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { parseJsonLoose } from "./json.js";
|
|
2
|
+
import { MemoryModelError } from "./model-error.js";
|
|
3
|
+
const PROMPT = (text) => `Extract durable memories from the text below as a JSON array.
|
|
4
|
+
Each item: {"type":"task|event|note","text":"<one atomic sentence>","salience":0..1,"isInsight":true|false}.
|
|
5
|
+
Rules: one fact per item; <=160 chars; omit chit-chat; salience reflects long-term importance; isInsight=true only for synthesized higher-level conclusions. Return ONLY the JSON array.
|
|
6
|
+
|
|
7
|
+
TEXT:
|
|
8
|
+
${text}`;
|
|
9
|
+
export async function distill(text, llm) {
|
|
10
|
+
if (text.trim().length === 0)
|
|
11
|
+
return [];
|
|
12
|
+
let raw;
|
|
13
|
+
try {
|
|
14
|
+
raw = await llm.complete(PROMPT(text), { label: "capture:distill" });
|
|
15
|
+
}
|
|
16
|
+
catch (cause) {
|
|
17
|
+
// Surface model outages (Ollama down, timeout, 5xx) instead of returning [] — an empty result is
|
|
18
|
+
// indistinguishable from "nothing worth remembering", which is exactly how a dead model hides.
|
|
19
|
+
throw new MemoryModelError("llm", "distill", cause);
|
|
20
|
+
}
|
|
21
|
+
const parsed = parseJsonLoose(raw);
|
|
22
|
+
if (!Array.isArray(parsed))
|
|
23
|
+
return [];
|
|
24
|
+
return parsed.flatMap((it) => normalizeCandidate(it));
|
|
25
|
+
}
|
|
26
|
+
const VALID_TYPES = new Set(["task", "event", "note"]);
|
|
27
|
+
function normalizeCandidate(it) {
|
|
28
|
+
if (it === null || typeof it !== "object")
|
|
29
|
+
return [];
|
|
30
|
+
const obj = it;
|
|
31
|
+
// Require non-empty text, then normalize to a bullet-safe single line so it round-trips through
|
|
32
|
+
// serializeBullet (which rejects newlines and the `<!--mem` delimiter) instead of being silently
|
|
33
|
+
// dropped by reconcile's per-candidate isolation. Collapse whitespace, strip the delimiter, cap ~280.
|
|
34
|
+
const rawText = typeof obj["text"] === "string" ? obj["text"] : "";
|
|
35
|
+
const text = rawText.replace(/\s+/gu, " ").replace(/<!--mem/gu, "").trim().slice(0, 280);
|
|
36
|
+
if (text.length === 0)
|
|
37
|
+
return [];
|
|
38
|
+
// Coerce type to one of task/event/note (default "note")
|
|
39
|
+
const rawType = typeof obj["type"] === "string" ? obj["type"] : "";
|
|
40
|
+
const type = VALID_TYPES.has(rawType) ? rawType : "note";
|
|
41
|
+
// Clamp salience to [0,1] (default 0.5 when missing/non-finite)
|
|
42
|
+
const rawSalience = typeof obj["salience"] === "number" ? obj["salience"] : NaN;
|
|
43
|
+
const salience = Number.isFinite(rawSalience)
|
|
44
|
+
? Math.min(1, Math.max(0, rawSalience))
|
|
45
|
+
: 0.5;
|
|
46
|
+
// Coerce isInsight to boolean (default false)
|
|
47
|
+
const isInsight = typeof obj["isInsight"] === "boolean" ? obj["isInsight"] : false;
|
|
48
|
+
return [{ type, text, salience, isInsight }];
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=distill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"distill.js","sourceRoot":"","sources":["../../src/bujo/distill.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { LlmComplete } from "./llm.js";
|
|
2
|
+
export interface ExtractedEntity {
|
|
3
|
+
readonly id: string;
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly type?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ExtractedRelation {
|
|
8
|
+
readonly src: string;
|
|
9
|
+
readonly dst: string;
|
|
10
|
+
readonly relation: string;
|
|
11
|
+
}
|
|
12
|
+
export interface Extraction {
|
|
13
|
+
readonly entities: ExtractedEntity[];
|
|
14
|
+
readonly relations: ExtractedRelation[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Use the LLM to extract named entities and their relations from `text`.
|
|
18
|
+
* Empty/whitespace text → `{entities:[], relations:[]}`.
|
|
19
|
+
* Malformed LLM *output* is handled defensively (→ EMPTY), but a model *failure* (Ollama down,
|
|
20
|
+
* timeout, 5xx) is rethrown as a {@link MemoryModelError} so it surfaces rather than looking like
|
|
21
|
+
* "no entities found".
|
|
22
|
+
*/
|
|
23
|
+
export declare function extractEntities(text: string, llm: LlmComplete): Promise<Extraction>;
|
|
24
|
+
//# sourceMappingURL=entities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entities.d.ts","sourceRoot":"","sources":["../../src/bujo/entities.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAI5C,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,EAAE,CAAC;CACzC;AA2DD;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CA6BzF"}
|