@equationalapplications/expo-llm-wiki 0.0.0-development
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/LICENSE +21 -0
- package/README.md +259 -0
- package/dist/WikiMemory-B-yFw9Dc.d.mts +118 -0
- package/dist/WikiMemory-B-yFw9Dc.d.ts +118 -0
- package/dist/WikiMemory-BI2Aizwv.d.mts +121 -0
- package/dist/WikiMemory-BI2Aizwv.d.ts +121 -0
- package/dist/WikiMemory-BWTt1Ynm.d.mts +103 -0
- package/dist/WikiMemory-BWTt1Ynm.d.ts +103 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +679 -0
- package/dist/index.mjs +651 -0
- package/dist/react/index.d.mts +72 -0
- package/dist/react/index.d.ts +72 -0
- package/dist/react/index.js +230 -0
- package/dist/react/index.mjs +197 -0
- package/package.json +67 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Equational Applications
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
# expo-llm-wiki
|
|
2
|
+
|
|
3
|
+
Offline-first, SQLite-backed memory for LLM apps built with Expo. Handles FTS5 search, episodic event logging, background fact extraction, and memory healing — bring your own LLM.
|
|
4
|
+
|
|
5
|
+
## Key Principles
|
|
6
|
+
|
|
7
|
+
- **Bring Your Own Inference (BYOI):** Provide one `generateText` function. The package owns prompt construction, JSON parsing, and database writes.
|
|
8
|
+
- **Namespace Safe:** All tables are prefixed (default: `llm_wiki_`) — no collisions with your existing database.
|
|
9
|
+
- **Multi-Entity:** Multiple independent "brains" in one database via `entityId`.
|
|
10
|
+
- **Offline First:** Reads are fully local via SQLite FTS5, typically under 50ms.
|
|
11
|
+
- **Full Unicode Support:** UTF-8 and UTF-16 (including surrogate pairs for emoji) are fully supported. Chunks are split safely at sentence boundaries; surrogate pairs are never fragmented.
|
|
12
|
+
|
|
13
|
+
## How It Works
|
|
14
|
+
|
|
15
|
+
```mermaid
|
|
16
|
+
flowchart LR
|
|
17
|
+
subgraph API
|
|
18
|
+
direction TB
|
|
19
|
+
write["write(event)"]
|
|
20
|
+
ingest["ingestDocument()"]
|
|
21
|
+
librarian["runLibrarian()"]
|
|
22
|
+
heal["runHeal()"]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
subgraph SQLite
|
|
26
|
+
direction TB
|
|
27
|
+
events[(events)]
|
|
28
|
+
entries[("entries\n(facts)")]
|
|
29
|
+
tasks[(tasks)]
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
LLM["LLMProvider\n.generateText()"]
|
|
33
|
+
|
|
34
|
+
read["read(entityId, query)"]
|
|
35
|
+
FTS5(["FTS5 search"])
|
|
36
|
+
Bundle(["MemoryBundle\nfacts · tasks · events"])
|
|
37
|
+
|
|
38
|
+
write --> events
|
|
39
|
+
events -. "≥ threshold" .-> librarian
|
|
40
|
+
librarian --> LLM
|
|
41
|
+
heal --> LLM
|
|
42
|
+
ingest --> LLM
|
|
43
|
+
LLM --> entries
|
|
44
|
+
LLM --> tasks
|
|
45
|
+
|
|
46
|
+
read --> FTS5
|
|
47
|
+
FTS5 --> entries
|
|
48
|
+
entries --> Bundle
|
|
49
|
+
tasks --> Bundle
|
|
50
|
+
events --> Bundle
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Installation
|
|
54
|
+
|
|
55
|
+
In your Expo project:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
npx expo install expo-sqlite
|
|
59
|
+
npm install expo-llm-wiki
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Use `npx expo install` for `expo-sqlite` so Expo's version resolver picks the correct native build for your SDK version.
|
|
63
|
+
|
|
64
|
+
## Setup
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { createWiki } from 'expo-llm-wiki';
|
|
68
|
+
import * as SQLite from 'expo-sqlite';
|
|
69
|
+
|
|
70
|
+
const db = await SQLite.openDatabaseAsync('my-app.db');
|
|
71
|
+
|
|
72
|
+
const wiki = createWiki(db, {
|
|
73
|
+
llmProvider: {
|
|
74
|
+
generateText: async ({ systemPrompt, userPrompt }) => {
|
|
75
|
+
// Connect to OpenAI, Gemini, a local model, etc.
|
|
76
|
+
// Must return a raw string (JSON, optionally in a markdown code fence).
|
|
77
|
+
const response = await openai.chat.completions.create({
|
|
78
|
+
model: 'gpt-4o-mini',
|
|
79
|
+
messages: [
|
|
80
|
+
{ role: 'system', content: systemPrompt },
|
|
81
|
+
{ role: 'user', content: userPrompt },
|
|
82
|
+
],
|
|
83
|
+
});
|
|
84
|
+
return response.choices[0].message.content ?? '{}';
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
config: {
|
|
88
|
+
tablePrefix: 'llm_wiki_', // optional, default: 'llm_wiki_'
|
|
89
|
+
maxFtsResults: 10, // optional, default: 10
|
|
90
|
+
autoLibrarianThreshold: 20, // optional, default: 20
|
|
91
|
+
maxChunkLength: 6000, // optional, default: 6000 (char count, not bytes)
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Create tables and FTS5 indexes (call once on app startup)
|
|
96
|
+
await wiki.setup();
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Core API
|
|
100
|
+
|
|
101
|
+
### Read
|
|
102
|
+
|
|
103
|
+
FTS5 full-text search over facts, plus open tasks and recent events:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
const { facts, tasks, events } = await wiki.read('entity-123', 'weekend plans');
|
|
107
|
+
// facts: WikiFact[] — matched by FTS5, ranked by confidence + access count
|
|
108
|
+
// tasks: WikiTask[] — pending and in-progress only
|
|
109
|
+
// events: WikiEvent[] — 10 most recent, ascending
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Pass an empty string to skip FTS and return the most recently updated facts.
|
|
113
|
+
|
|
114
|
+
### Write
|
|
115
|
+
|
|
116
|
+
Log an episodic event. Automatically triggers the librarian pass once enough events accumulate:
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
await wiki.write('entity-123', {
|
|
120
|
+
event_type: 'observation',
|
|
121
|
+
summary: 'User mentioned they love hiking on weekends.',
|
|
122
|
+
});
|
|
123
|
+
// event_type: 'observation' | 'decision' | 'action' | 'outcome'
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Ingest Document
|
|
127
|
+
|
|
128
|
+
Extract facts from a document (chunked internally). Idempotent — re-calling with the same `sourceRef` replaces the prior extraction. Documents are automatically chunked at sentence boundaries; if a sentence exceeds `maxChunkLength`, it is hard-split.
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
const result = await wiki.ingestDocument('entity-123', {
|
|
132
|
+
// sourceRef is normalized: only [A-Za-z0-9._\- ] are kept, all other characters
|
|
133
|
+
// (including `/`) are stripped. Use underscores or dots as path separators to
|
|
134
|
+
// avoid accidental collisions (e.g. 'docs_preferences.md' not 'docs/preferences.md').
|
|
135
|
+
sourceRef: 'preferences.md', // stable identifier
|
|
136
|
+
sourceHash: sha256(content), // for change detection
|
|
137
|
+
documentChunk: content,
|
|
138
|
+
maxChunkLength: 6000, // optional, character count
|
|
139
|
+
});
|
|
140
|
+
// result: { truncated: boolean; chunks: number }
|
|
141
|
+
// truncated: true if at least one hard-split was required (no sentence boundary)
|
|
142
|
+
// chunks: number of LLM calls made
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Background Maintenance
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
// Consolidate recent events into durable facts (auto-triggered by write, or call manually)
|
|
149
|
+
await wiki.runLibrarian('entity-123');
|
|
150
|
+
|
|
151
|
+
// Resolve contradictions, downgrade stale claims, remove obsolete facts
|
|
152
|
+
await wiki.runHeal('entity-123');
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Forget
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
const result = await wiki.forget('entity-123', { entryId: 'fact_abc' }); // single fact
|
|
159
|
+
// result: { deleted: { entries: number; tasks: number } }
|
|
160
|
+
|
|
161
|
+
await wiki.forget('entity-123', { taskId: 'task_xyz' }); // single task
|
|
162
|
+
// sourceRef is normalized the same way as in ingestDocument (slashes stripped)
|
|
163
|
+
await wiki.forget('entity-123', { sourceRef: 'x.md' }); // all facts from a document
|
|
164
|
+
await wiki.forget('entity-123', { clearAll: true }); // wipe entity
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Throws `Error` if `sourceRef` or `sourceHash` is provided but invalid. Soft-deletes are idempotent — calling again with the same parameters returns `{ deleted: { entries: 0; tasks: 0 } }`.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## React / Expo Component API
|
|
172
|
+
|
|
173
|
+
Import from `expo-llm-wiki/react`. This entry point is separate so non-React consumers do not transitively import React.
|
|
174
|
+
|
|
175
|
+
### Provider
|
|
176
|
+
|
|
177
|
+
Wrap once at app root (or any subtree that needs memory access):
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
import { WikiProvider } from 'expo-llm-wiki/react';
|
|
181
|
+
import { createWiki } from 'expo-llm-wiki';
|
|
182
|
+
|
|
183
|
+
const wiki = createWiki(db, { llmProvider });
|
|
184
|
+
|
|
185
|
+
export default function App() {
|
|
186
|
+
return (
|
|
187
|
+
<WikiProvider wiki={wiki}>
|
|
188
|
+
<YourApp />
|
|
189
|
+
</WikiProvider>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### `useMemoryRead(entityId, query)`
|
|
195
|
+
|
|
196
|
+
Reactive read. Fetches on mount and whenever `entityId` or `query` changes. In-flight results always land before a queued re-fetch starts — results are never silently discarded.
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
const { data, isPending, error, refetch } = useMemoryRead('entity-123', 'weekend plans');
|
|
200
|
+
// data: MemoryBundle | null
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### `useWikiWrite()`
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
const { execute, isPending, error } = useWikiWrite();
|
|
207
|
+
|
|
208
|
+
await execute('entity-123', {
|
|
209
|
+
event_type: 'observation',
|
|
210
|
+
summary: 'User mentioned they love hiking.',
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### `useWikiMaintenance()`
|
|
215
|
+
|
|
216
|
+
Shared `isPending` — true if either operation is in-flight:
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
const { runLibrarian, runHeal, isPending, error } = useWikiMaintenance();
|
|
220
|
+
|
|
221
|
+
await runLibrarian('entity-123');
|
|
222
|
+
await runHeal('entity-123');
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### `useWikiIngest()`
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
const { execute, lastResult, isPending, error } = useWikiIngest();
|
|
229
|
+
// lastResult: { truncated: boolean; chunks: number } | null
|
|
230
|
+
|
|
231
|
+
const result = await execute('entity-123', {
|
|
232
|
+
sourceRef: 'preferences.md', // slashes are stripped by normalizeSourceRef
|
|
233
|
+
sourceHash: sha256(content),
|
|
234
|
+
documentChunk: content,
|
|
235
|
+
});
|
|
236
|
+
// result.truncated — true if any hard-splits were required
|
|
237
|
+
// result.chunks — number of LLM calls made
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### `useWikiForget()`
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
const { execute, lastResult, isPending, error } = useWikiForget();
|
|
244
|
+
// lastResult: { deleted: { entries: number; tasks: number } } | null
|
|
245
|
+
|
|
246
|
+
const result = await execute('entity-123', { entryId: 'fact_abc' });
|
|
247
|
+
// result.deleted.entries — rows soft-deleted
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
All mutation hooks follow the same pattern (`TResult` is specific per hook):
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
{
|
|
254
|
+
execute: (...args) => Promise<TResult>;
|
|
255
|
+
lastResult: TResult | null; // result of the last successful call; null before first call or after an error
|
|
256
|
+
isPending: boolean;
|
|
257
|
+
error: Error | null; // cleared on the next execute call
|
|
258
|
+
}
|
|
259
|
+
```
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import * as SQLite from 'expo-sqlite';
|
|
2
|
+
|
|
3
|
+
interface WikiConfig {
|
|
4
|
+
tablePrefix?: string;
|
|
5
|
+
maxFtsResults?: number;
|
|
6
|
+
pruneEventsAfter?: number;
|
|
7
|
+
autoLibrarianThreshold?: number;
|
|
8
|
+
autoHealThreshold?: number;
|
|
9
|
+
orphanAfterDays?: number | null;
|
|
10
|
+
staleInferredAfterDays?: number | null;
|
|
11
|
+
maxChunkBytes?: number;
|
|
12
|
+
}
|
|
13
|
+
interface WikiFact {
|
|
14
|
+
id: string;
|
|
15
|
+
entity_id: string;
|
|
16
|
+
title: string;
|
|
17
|
+
body: string;
|
|
18
|
+
tags: string[];
|
|
19
|
+
confidence: 'certain' | 'inferred' | 'tentative';
|
|
20
|
+
source_type: 'user_stated' | 'agent_inferred' | 'user_confirmed' | 'user_document';
|
|
21
|
+
source_hash: string | null;
|
|
22
|
+
source_ref: string | null;
|
|
23
|
+
created_at: number;
|
|
24
|
+
updated_at: number;
|
|
25
|
+
last_accessed_at: number | null;
|
|
26
|
+
access_count: number;
|
|
27
|
+
deleted_at: number | null;
|
|
28
|
+
}
|
|
29
|
+
interface WikiTask {
|
|
30
|
+
id: string;
|
|
31
|
+
entity_id: string;
|
|
32
|
+
description: string;
|
|
33
|
+
status: 'pending' | 'in_progress' | 'done' | 'abandoned';
|
|
34
|
+
priority: number;
|
|
35
|
+
created_at: number;
|
|
36
|
+
updated_at: number;
|
|
37
|
+
resolved_at: number | null;
|
|
38
|
+
deleted_at: number | null;
|
|
39
|
+
}
|
|
40
|
+
interface WikiEvent {
|
|
41
|
+
id: string;
|
|
42
|
+
entity_id: string;
|
|
43
|
+
event_type: 'observation' | 'decision' | 'action' | 'outcome';
|
|
44
|
+
summary: string;
|
|
45
|
+
related_entry_id?: string | null;
|
|
46
|
+
created_at: number;
|
|
47
|
+
}
|
|
48
|
+
interface WikiCheckpoint {
|
|
49
|
+
entity_id: string;
|
|
50
|
+
heal_checkpoint: number;
|
|
51
|
+
memory_checkpoint: number;
|
|
52
|
+
}
|
|
53
|
+
interface ExtractedFact {
|
|
54
|
+
title: string;
|
|
55
|
+
body: string;
|
|
56
|
+
tags: string[];
|
|
57
|
+
confidence: 'certain' | 'inferred' | 'tentative';
|
|
58
|
+
}
|
|
59
|
+
interface ExtractedTask {
|
|
60
|
+
description: string;
|
|
61
|
+
priority: number;
|
|
62
|
+
}
|
|
63
|
+
interface LLMProvider {
|
|
64
|
+
/**
|
|
65
|
+
* Generates text using the developer's LLM of choice.
|
|
66
|
+
* Expected to return the raw text response (typically a JSON string).
|
|
67
|
+
*/
|
|
68
|
+
generateText: (params: {
|
|
69
|
+
systemPrompt: string;
|
|
70
|
+
userPrompt: string;
|
|
71
|
+
}) => Promise<string>;
|
|
72
|
+
}
|
|
73
|
+
interface WikiOptions {
|
|
74
|
+
config?: WikiConfig;
|
|
75
|
+
llmProvider: LLMProvider;
|
|
76
|
+
}
|
|
77
|
+
interface MemoryBundle {
|
|
78
|
+
facts: WikiFact[];
|
|
79
|
+
tasks: WikiTask[];
|
|
80
|
+
events: WikiEvent[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
declare class WikiMemory {
|
|
84
|
+
private db;
|
|
85
|
+
private prefix;
|
|
86
|
+
private options;
|
|
87
|
+
constructor(db: SQLite.SQLiteDatabase, options: WikiOptions);
|
|
88
|
+
setup(): Promise<void>;
|
|
89
|
+
private formatSearchQuery;
|
|
90
|
+
read(entityId: string, query: string): Promise<MemoryBundle>;
|
|
91
|
+
write(entityId: string, event: Omit<WikiEvent, 'id' | 'entity_id' | 'created_at'>): Promise<void>;
|
|
92
|
+
private runLibrarianThenMaybeHeal;
|
|
93
|
+
runLibrarian(entityId: string): Promise<void>;
|
|
94
|
+
runHeal(entityId: string): Promise<void>;
|
|
95
|
+
forget(entityId: string, params: {
|
|
96
|
+
entryId?: string;
|
|
97
|
+
taskId?: string;
|
|
98
|
+
sourceRef?: string;
|
|
99
|
+
sourceHash?: string;
|
|
100
|
+
clearAll?: boolean;
|
|
101
|
+
}): Promise<{
|
|
102
|
+
deleted: {
|
|
103
|
+
entries: number;
|
|
104
|
+
tasks: number;
|
|
105
|
+
};
|
|
106
|
+
}>;
|
|
107
|
+
ingestDocument(entityId: string, params: {
|
|
108
|
+
sourceRef: string;
|
|
109
|
+
sourceHash: string;
|
|
110
|
+
documentChunk: string;
|
|
111
|
+
maxChunkBytes?: number;
|
|
112
|
+
}): Promise<{
|
|
113
|
+
truncated: boolean;
|
|
114
|
+
chunks: number;
|
|
115
|
+
}>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export { type ExtractedFact as E, type LLMProvider as L, type MemoryBundle as M, type WikiOptions as W, WikiMemory as a, type ExtractedTask as b, type WikiCheckpoint as c, type WikiConfig as d, type WikiEvent as e, type WikiFact as f, type WikiTask as g };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import * as SQLite from 'expo-sqlite';
|
|
2
|
+
|
|
3
|
+
interface WikiConfig {
|
|
4
|
+
tablePrefix?: string;
|
|
5
|
+
maxFtsResults?: number;
|
|
6
|
+
pruneEventsAfter?: number;
|
|
7
|
+
autoLibrarianThreshold?: number;
|
|
8
|
+
autoHealThreshold?: number;
|
|
9
|
+
orphanAfterDays?: number | null;
|
|
10
|
+
staleInferredAfterDays?: number | null;
|
|
11
|
+
maxChunkBytes?: number;
|
|
12
|
+
}
|
|
13
|
+
interface WikiFact {
|
|
14
|
+
id: string;
|
|
15
|
+
entity_id: string;
|
|
16
|
+
title: string;
|
|
17
|
+
body: string;
|
|
18
|
+
tags: string[];
|
|
19
|
+
confidence: 'certain' | 'inferred' | 'tentative';
|
|
20
|
+
source_type: 'user_stated' | 'agent_inferred' | 'user_confirmed' | 'user_document';
|
|
21
|
+
source_hash: string | null;
|
|
22
|
+
source_ref: string | null;
|
|
23
|
+
created_at: number;
|
|
24
|
+
updated_at: number;
|
|
25
|
+
last_accessed_at: number | null;
|
|
26
|
+
access_count: number;
|
|
27
|
+
deleted_at: number | null;
|
|
28
|
+
}
|
|
29
|
+
interface WikiTask {
|
|
30
|
+
id: string;
|
|
31
|
+
entity_id: string;
|
|
32
|
+
description: string;
|
|
33
|
+
status: 'pending' | 'in_progress' | 'done' | 'abandoned';
|
|
34
|
+
priority: number;
|
|
35
|
+
created_at: number;
|
|
36
|
+
updated_at: number;
|
|
37
|
+
resolved_at: number | null;
|
|
38
|
+
deleted_at: number | null;
|
|
39
|
+
}
|
|
40
|
+
interface WikiEvent {
|
|
41
|
+
id: string;
|
|
42
|
+
entity_id: string;
|
|
43
|
+
event_type: 'observation' | 'decision' | 'action' | 'outcome';
|
|
44
|
+
summary: string;
|
|
45
|
+
related_entry_id?: string | null;
|
|
46
|
+
created_at: number;
|
|
47
|
+
}
|
|
48
|
+
interface WikiCheckpoint {
|
|
49
|
+
entity_id: string;
|
|
50
|
+
heal_checkpoint: number;
|
|
51
|
+
memory_checkpoint: number;
|
|
52
|
+
}
|
|
53
|
+
interface ExtractedFact {
|
|
54
|
+
title: string;
|
|
55
|
+
body: string;
|
|
56
|
+
tags: string[];
|
|
57
|
+
confidence: 'certain' | 'inferred' | 'tentative';
|
|
58
|
+
}
|
|
59
|
+
interface ExtractedTask {
|
|
60
|
+
description: string;
|
|
61
|
+
priority: number;
|
|
62
|
+
}
|
|
63
|
+
interface LLMProvider {
|
|
64
|
+
/**
|
|
65
|
+
* Generates text using the developer's LLM of choice.
|
|
66
|
+
* Expected to return the raw text response (typically a JSON string).
|
|
67
|
+
*/
|
|
68
|
+
generateText: (params: {
|
|
69
|
+
systemPrompt: string;
|
|
70
|
+
userPrompt: string;
|
|
71
|
+
}) => Promise<string>;
|
|
72
|
+
}
|
|
73
|
+
interface WikiOptions {
|
|
74
|
+
config?: WikiConfig;
|
|
75
|
+
llmProvider: LLMProvider;
|
|
76
|
+
}
|
|
77
|
+
interface MemoryBundle {
|
|
78
|
+
facts: WikiFact[];
|
|
79
|
+
tasks: WikiTask[];
|
|
80
|
+
events: WikiEvent[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
declare class WikiMemory {
|
|
84
|
+
private db;
|
|
85
|
+
private prefix;
|
|
86
|
+
private options;
|
|
87
|
+
constructor(db: SQLite.SQLiteDatabase, options: WikiOptions);
|
|
88
|
+
setup(): Promise<void>;
|
|
89
|
+
private formatSearchQuery;
|
|
90
|
+
read(entityId: string, query: string): Promise<MemoryBundle>;
|
|
91
|
+
write(entityId: string, event: Omit<WikiEvent, 'id' | 'entity_id' | 'created_at'>): Promise<void>;
|
|
92
|
+
private runLibrarianThenMaybeHeal;
|
|
93
|
+
runLibrarian(entityId: string): Promise<void>;
|
|
94
|
+
runHeal(entityId: string): Promise<void>;
|
|
95
|
+
forget(entityId: string, params: {
|
|
96
|
+
entryId?: string;
|
|
97
|
+
taskId?: string;
|
|
98
|
+
sourceRef?: string;
|
|
99
|
+
sourceHash?: string;
|
|
100
|
+
clearAll?: boolean;
|
|
101
|
+
}): Promise<{
|
|
102
|
+
deleted: {
|
|
103
|
+
entries: number;
|
|
104
|
+
tasks: number;
|
|
105
|
+
};
|
|
106
|
+
}>;
|
|
107
|
+
ingestDocument(entityId: string, params: {
|
|
108
|
+
sourceRef: string;
|
|
109
|
+
sourceHash: string;
|
|
110
|
+
documentChunk: string;
|
|
111
|
+
maxChunkBytes?: number;
|
|
112
|
+
}): Promise<{
|
|
113
|
+
truncated: boolean;
|
|
114
|
+
chunks: number;
|
|
115
|
+
}>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export { type ExtractedFact as E, type LLMProvider as L, type MemoryBundle as M, type WikiOptions as W, WikiMemory as a, type ExtractedTask as b, type WikiCheckpoint as c, type WikiConfig as d, type WikiEvent as e, type WikiFact as f, type WikiTask as g };
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import * as SQLite from 'expo-sqlite';
|
|
2
|
+
|
|
3
|
+
interface WikiConfig {
|
|
4
|
+
tablePrefix?: string;
|
|
5
|
+
maxFtsResults?: number;
|
|
6
|
+
pruneEventsAfter?: number;
|
|
7
|
+
autoLibrarianThreshold?: number;
|
|
8
|
+
autoHealThreshold?: number;
|
|
9
|
+
orphanAfterDays?: number | null;
|
|
10
|
+
staleInferredAfterDays?: number | null;
|
|
11
|
+
maxChunkLength?: number;
|
|
12
|
+
}
|
|
13
|
+
interface WikiFact {
|
|
14
|
+
id: string;
|
|
15
|
+
entity_id: string;
|
|
16
|
+
title: string;
|
|
17
|
+
body: string;
|
|
18
|
+
tags: string[];
|
|
19
|
+
confidence: 'certain' | 'inferred' | 'tentative';
|
|
20
|
+
source_type: 'user_stated' | 'agent_inferred' | 'user_confirmed' | 'user_document';
|
|
21
|
+
source_hash: string | null;
|
|
22
|
+
source_ref: string | null;
|
|
23
|
+
created_at: number;
|
|
24
|
+
updated_at: number;
|
|
25
|
+
last_accessed_at: number | null;
|
|
26
|
+
access_count: number;
|
|
27
|
+
deleted_at: number | null;
|
|
28
|
+
}
|
|
29
|
+
interface WikiTask {
|
|
30
|
+
id: string;
|
|
31
|
+
entity_id: string;
|
|
32
|
+
description: string;
|
|
33
|
+
status: 'pending' | 'in_progress' | 'done' | 'abandoned';
|
|
34
|
+
priority: number;
|
|
35
|
+
created_at: number;
|
|
36
|
+
updated_at: number;
|
|
37
|
+
resolved_at: number | null;
|
|
38
|
+
deleted_at: number | null;
|
|
39
|
+
}
|
|
40
|
+
interface WikiEvent {
|
|
41
|
+
id: string;
|
|
42
|
+
entity_id: string;
|
|
43
|
+
event_type: 'observation' | 'decision' | 'action' | 'outcome';
|
|
44
|
+
summary: string;
|
|
45
|
+
related_entry_id?: string | null;
|
|
46
|
+
created_at: number;
|
|
47
|
+
}
|
|
48
|
+
interface WikiCheckpoint {
|
|
49
|
+
entity_id: string;
|
|
50
|
+
heal_checkpoint: number;
|
|
51
|
+
memory_checkpoint: number;
|
|
52
|
+
}
|
|
53
|
+
interface ExtractedFact {
|
|
54
|
+
title: string;
|
|
55
|
+
body: string;
|
|
56
|
+
tags: string[];
|
|
57
|
+
confidence: 'certain' | 'inferred' | 'tentative';
|
|
58
|
+
}
|
|
59
|
+
interface ExtractedTask {
|
|
60
|
+
description: string;
|
|
61
|
+
priority: number;
|
|
62
|
+
}
|
|
63
|
+
interface LLMProvider {
|
|
64
|
+
/**
|
|
65
|
+
* Generates text using the developer's LLM of choice.
|
|
66
|
+
* Expected to return the raw text response (typically a JSON string).
|
|
67
|
+
*/
|
|
68
|
+
generateText: (params: {
|
|
69
|
+
systemPrompt: string;
|
|
70
|
+
userPrompt: string;
|
|
71
|
+
}) => Promise<string>;
|
|
72
|
+
}
|
|
73
|
+
interface WikiOptions {
|
|
74
|
+
config?: WikiConfig;
|
|
75
|
+
llmProvider: LLMProvider;
|
|
76
|
+
}
|
|
77
|
+
interface MemoryBundle {
|
|
78
|
+
facts: WikiFact[];
|
|
79
|
+
tasks: WikiTask[];
|
|
80
|
+
events: WikiEvent[];
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
declare class WikiMemory {
|
|
84
|
+
private db;
|
|
85
|
+
private prefix;
|
|
86
|
+
private options;
|
|
87
|
+
private activeMaintenanceJobs;
|
|
88
|
+
constructor(db: SQLite.SQLiteDatabase, options: WikiOptions);
|
|
89
|
+
setup(): Promise<void>;
|
|
90
|
+
private formatSearchQuery;
|
|
91
|
+
read(entityId: string, query: string): Promise<MemoryBundle>;
|
|
92
|
+
write(entityId: string, event: Omit<WikiEvent, 'id' | 'entity_id' | 'created_at'>): Promise<void>;
|
|
93
|
+
private runLibrarianThenMaybeHeal;
|
|
94
|
+
private _doRunLibrarian;
|
|
95
|
+
private _doRunHeal;
|
|
96
|
+
runLibrarian(entityId: string): Promise<void>;
|
|
97
|
+
runHeal(entityId: string): Promise<void>;
|
|
98
|
+
forget(entityId: string, params: {
|
|
99
|
+
entryId?: string;
|
|
100
|
+
taskId?: string;
|
|
101
|
+
sourceRef?: string;
|
|
102
|
+
sourceHash?: string;
|
|
103
|
+
clearAll?: boolean;
|
|
104
|
+
}): Promise<{
|
|
105
|
+
deleted: {
|
|
106
|
+
entries: number;
|
|
107
|
+
tasks: number;
|
|
108
|
+
};
|
|
109
|
+
}>;
|
|
110
|
+
ingestDocument(entityId: string, params: {
|
|
111
|
+
sourceRef: string;
|
|
112
|
+
sourceHash: string;
|
|
113
|
+
documentChunk: string;
|
|
114
|
+
maxChunkLength?: number;
|
|
115
|
+
}): Promise<{
|
|
116
|
+
truncated: boolean;
|
|
117
|
+
chunks: number;
|
|
118
|
+
}>;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export { type ExtractedFact as E, type LLMProvider as L, type MemoryBundle as M, type WikiOptions as W, WikiMemory as a, type ExtractedTask as b, type WikiCheckpoint as c, type WikiConfig as d, type WikiEvent as e, type WikiFact as f, type WikiTask as g };
|