audrey 0.16.1 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +146 -724
- package/dist/mcp-server/config.d.ts +20 -0
- package/dist/mcp-server/config.d.ts.map +1 -0
- package/dist/mcp-server/config.js +125 -0
- package/dist/mcp-server/config.js.map +1 -0
- package/dist/mcp-server/index.d.ts +100 -0
- package/dist/mcp-server/index.d.ts.map +1 -0
- package/dist/mcp-server/index.js +1113 -0
- package/dist/mcp-server/index.js.map +1 -0
- package/dist/src/adaptive.d.ts +7 -0
- package/dist/src/adaptive.d.ts.map +1 -0
- package/dist/src/adaptive.js +49 -0
- package/dist/src/adaptive.js.map +1 -0
- package/dist/src/affect.d.ts +19 -0
- package/dist/src/affect.d.ts.map +1 -0
- package/dist/src/affect.js +72 -0
- package/dist/src/affect.js.map +1 -0
- package/dist/src/audrey.d.ts +140 -0
- package/dist/src/audrey.d.ts.map +1 -0
- package/dist/src/audrey.js +564 -0
- package/dist/src/audrey.js.map +1 -0
- package/dist/src/capsule.d.ts +68 -0
- package/dist/src/capsule.d.ts.map +1 -0
- package/dist/src/capsule.js +311 -0
- package/dist/src/capsule.js.map +1 -0
- package/dist/src/causal.d.ts +28 -0
- package/dist/src/causal.d.ts.map +1 -0
- package/dist/src/causal.js +65 -0
- package/dist/src/causal.js.map +1 -0
- package/dist/src/confidence.d.ts +12 -0
- package/dist/src/confidence.d.ts.map +1 -0
- package/dist/src/confidence.js +63 -0
- package/dist/src/confidence.js.map +1 -0
- package/dist/src/consolidate.d.ts +8 -0
- package/dist/src/consolidate.d.ts.map +1 -0
- package/dist/src/consolidate.js +218 -0
- package/dist/src/consolidate.js.map +1 -0
- package/dist/src/context.d.ts +3 -0
- package/dist/src/context.d.ts.map +1 -0
- package/dist/src/context.js +19 -0
- package/dist/src/context.js.map +1 -0
- package/dist/src/db.d.ts +12 -0
- package/dist/src/db.d.ts.map +1 -0
- package/dist/src/db.js +380 -0
- package/dist/src/db.js.map +1 -0
- package/dist/src/decay.d.ts +7 -0
- package/dist/src/decay.d.ts.map +1 -0
- package/dist/src/decay.js +68 -0
- package/dist/src/decay.js.map +1 -0
- package/dist/src/embedding.d.ts +57 -0
- package/dist/src/embedding.d.ts.map +1 -0
- package/dist/src/embedding.js +254 -0
- package/dist/src/embedding.js.map +1 -0
- package/dist/src/encode.d.ts +15 -0
- package/dist/src/encode.d.ts.map +1 -0
- package/dist/src/encode.js +36 -0
- package/dist/src/encode.js.map +1 -0
- package/dist/src/events.d.ts +69 -0
- package/dist/src/events.d.ts.map +1 -0
- package/dist/src/events.js +149 -0
- package/dist/src/events.js.map +1 -0
- package/dist/src/export.d.ts +3 -0
- package/dist/src/export.d.ts.map +1 -0
- package/dist/src/export.js +46 -0
- package/dist/src/export.js.map +1 -0
- package/dist/src/forget.d.ts +11 -0
- package/dist/src/forget.d.ts.map +1 -0
- package/dist/src/forget.js +105 -0
- package/dist/src/forget.js.map +1 -0
- package/dist/src/fts.d.ts +34 -0
- package/dist/src/fts.d.ts.map +1 -0
- package/dist/src/fts.js +117 -0
- package/dist/src/fts.js.map +1 -0
- package/dist/src/hybrid-recall.d.ts +37 -0
- package/dist/src/hybrid-recall.d.ts.map +1 -0
- package/dist/src/hybrid-recall.js +213 -0
- package/dist/src/hybrid-recall.js.map +1 -0
- package/dist/src/import.d.ts +4 -0
- package/dist/src/import.d.ts.map +1 -0
- package/dist/src/import.js +127 -0
- package/dist/src/import.js.map +1 -0
- package/dist/src/index.d.ts +22 -0
- package/dist/src/index.d.ts.map +1 -0
- package/{src → dist/src}/index.js +5 -13
- package/dist/src/index.js.map +1 -0
- package/dist/src/interference.d.ts +13 -0
- package/dist/src/interference.d.ts.map +1 -0
- package/dist/src/interference.js +45 -0
- package/dist/src/interference.js.map +1 -0
- package/dist/src/introspect.d.ts +4 -0
- package/dist/src/introspect.d.ts.map +1 -0
- package/dist/src/introspect.js +40 -0
- package/dist/src/introspect.js.map +1 -0
- package/dist/src/llm.d.ts +38 -0
- package/dist/src/llm.d.ts.map +1 -0
- package/dist/src/llm.js +167 -0
- package/dist/src/llm.js.map +1 -0
- package/dist/src/migrate.d.ts +6 -0
- package/dist/src/migrate.d.ts.map +1 -0
- package/dist/src/migrate.js +51 -0
- package/dist/src/migrate.js.map +1 -0
- package/dist/src/promote.d.ts +40 -0
- package/dist/src/promote.d.ts.map +1 -0
- package/dist/src/promote.js +200 -0
- package/dist/src/promote.js.map +1 -0
- package/dist/src/prompts.d.ts +16 -0
- package/dist/src/prompts.d.ts.map +1 -0
- package/{src → dist/src}/prompts.js +172 -203
- package/dist/src/prompts.js.map +1 -0
- package/dist/src/recall.d.ts +9 -0
- package/dist/src/recall.d.ts.map +1 -0
- package/dist/src/recall.js +432 -0
- package/dist/src/recall.js.map +1 -0
- package/dist/src/redact.d.ts +27 -0
- package/dist/src/redact.d.ts.map +1 -0
- package/dist/src/redact.js +228 -0
- package/dist/src/redact.js.map +1 -0
- package/dist/src/rollback.d.ts +8 -0
- package/dist/src/rollback.d.ts.map +1 -0
- package/dist/src/rollback.js +33 -0
- package/dist/src/rollback.js.map +1 -0
- package/dist/src/routes.d.ts +7 -0
- package/dist/src/routes.d.ts.map +1 -0
- package/dist/src/routes.js +226 -0
- package/dist/src/routes.js.map +1 -0
- package/dist/src/rules-compiler.d.ts +20 -0
- package/dist/src/rules-compiler.d.ts.map +1 -0
- package/dist/src/rules-compiler.js +143 -0
- package/dist/src/rules-compiler.js.map +1 -0
- package/dist/src/server.d.ts +12 -0
- package/dist/src/server.d.ts.map +1 -0
- package/dist/src/server.js +22 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/tool-trace.d.ts +37 -0
- package/dist/src/tool-trace.d.ts.map +1 -0
- package/dist/src/tool-trace.js +142 -0
- package/dist/src/tool-trace.js.map +1 -0
- package/dist/src/types.d.ts +446 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +6 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/ulid.d.ts +3 -0
- package/dist/src/ulid.d.ts.map +1 -0
- package/dist/src/ulid.js +11 -0
- package/dist/src/ulid.js.map +1 -0
- package/dist/src/utils.d.ts +10 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +41 -0
- package/dist/src/utils.js.map +1 -0
- package/dist/src/validate.d.ts +22 -0
- package/dist/src/validate.d.ts.map +1 -0
- package/dist/src/validate.js +109 -0
- package/dist/src/validate.js.map +1 -0
- package/docs/assets/benchmarks/local-benchmark.svg +45 -0
- package/docs/assets/benchmarks/operations-benchmark.svg +45 -0
- package/docs/assets/benchmarks/published-memory-standards.svg +50 -0
- package/docs/benchmarking.md +151 -0
- package/docs/production-readiness.md +124 -0
- package/examples/fintech-ops-demo.js +67 -0
- package/examples/healthcare-ops-demo.js +67 -0
- package/examples/stripe-demo.js +105 -0
- package/package.json +53 -13
- package/mcp-server/config.js +0 -80
- package/mcp-server/index.js +0 -729
- package/src/adaptive.js +0 -53
- package/src/affect.js +0 -64
- package/src/audrey.js +0 -604
- package/src/causal.js +0 -95
- package/src/confidence.js +0 -120
- package/src/consolidate.js +0 -265
- package/src/context.js +0 -15
- package/src/db.js +0 -370
- package/src/decay.js +0 -84
- package/src/embedding.js +0 -256
- package/src/encode.js +0 -63
- package/src/export.js +0 -67
- package/src/forget.js +0 -111
- package/src/import.js +0 -245
- package/src/interference.js +0 -51
- package/src/introspect.js +0 -48
- package/src/llm.js +0 -246
- package/src/migrate.js +0 -58
- package/src/recall.js +0 -352
- package/src/rollback.js +0 -42
- package/src/ulid.js +0 -18
- package/src/utils.js +0 -38
- package/src/validate.js +0 -172
package/src/audrey.js
DELETED
|
@@ -1,604 +0,0 @@
|
|
|
1
|
-
import { EventEmitter } from 'node:events';
|
|
2
|
-
import { createDatabase, closeDatabase } from './db.js';
|
|
3
|
-
import { createEmbeddingProvider } from './embedding.js';
|
|
4
|
-
import { createLLMProvider } from './llm.js';
|
|
5
|
-
import { encodeEpisode } from './encode.js';
|
|
6
|
-
import { recall as recallFn, recallStream as recallStreamFn } from './recall.js';
|
|
7
|
-
import { validateMemory } from './validate.js';
|
|
8
|
-
import { runConsolidation } from './consolidate.js';
|
|
9
|
-
import { applyDecay } from './decay.js';
|
|
10
|
-
import { rollbackConsolidation, getConsolidationHistory } from './rollback.js';
|
|
11
|
-
import { forgetMemory, forgetByQuery as forgetByQueryFn, purgeMemories } from './forget.js';
|
|
12
|
-
import { introspect as introspectFn } from './introspect.js';
|
|
13
|
-
import { buildContextResolutionPrompt, buildReflectionPrompt } from './prompts.js';
|
|
14
|
-
import { exportMemories } from './export.js';
|
|
15
|
-
import { importMemories } from './import.js';
|
|
16
|
-
import { suggestConsolidationParams as suggestParamsFn } from './adaptive.js';
|
|
17
|
-
import { reembedAll } from './migrate.js';
|
|
18
|
-
import { applyInterference } from './interference.js';
|
|
19
|
-
import { detectResonance } from './affect.js';
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @typedef {'direct-observation' | 'told-by-user' | 'tool-result' | 'inference' | 'model-generated'} SourceType
|
|
23
|
-
* @typedef {'episodic' | 'semantic' | 'procedural'} MemoryType
|
|
24
|
-
*
|
|
25
|
-
* @typedef {Object} EncodeParams
|
|
26
|
-
* @property {string} content
|
|
27
|
-
* @property {SourceType} source
|
|
28
|
-
* @property {number} [salience]
|
|
29
|
-
* @property {{ trigger?: string, consequence?: string }} [causal]
|
|
30
|
-
* @property {string[]} [tags]
|
|
31
|
-
* @property {string} [supersedes]
|
|
32
|
-
* @property {Record<string, string>} [context]
|
|
33
|
-
* @property {{ valence?: number, arousal?: number, label?: string }} [affect]
|
|
34
|
-
*
|
|
35
|
-
* @typedef {Object} RecallOptions
|
|
36
|
-
* @property {number} [minConfidence]
|
|
37
|
-
* @property {MemoryType[]} [types]
|
|
38
|
-
* @property {number} [limit]
|
|
39
|
-
* @property {boolean} [includeProvenance]
|
|
40
|
-
* @property {boolean} [includeDormant]
|
|
41
|
-
* @property {string[]} [tags]
|
|
42
|
-
* @property {string[]} [sources]
|
|
43
|
-
* @property {string} [after]
|
|
44
|
-
* @property {string} [before]
|
|
45
|
-
* @property {Record<string, string>} [context]
|
|
46
|
-
* @property {{ valence?: number, arousal?: number }} [mood]
|
|
47
|
-
*
|
|
48
|
-
* @typedef {Object} RecallResult
|
|
49
|
-
* @property {string} id
|
|
50
|
-
* @property {string} content
|
|
51
|
-
* @property {MemoryType} type
|
|
52
|
-
* @property {number} confidence
|
|
53
|
-
* @property {number} score
|
|
54
|
-
* @property {string} source
|
|
55
|
-
* @property {string} createdAt
|
|
56
|
-
*
|
|
57
|
-
* @typedef {Object} ConsolidationResult
|
|
58
|
-
* @property {string} runId
|
|
59
|
-
* @property {number} episodesEvaluated
|
|
60
|
-
* @property {number} clustersFound
|
|
61
|
-
* @property {number} principlesExtracted
|
|
62
|
-
* @property {string} status
|
|
63
|
-
*
|
|
64
|
-
* @typedef {Object} IntrospectResult
|
|
65
|
-
* @property {number} episodic
|
|
66
|
-
* @property {number} semantic
|
|
67
|
-
* @property {number} procedural
|
|
68
|
-
* @property {number} causalLinks
|
|
69
|
-
* @property {number} dormant
|
|
70
|
-
* @property {{ open: number, resolved: number, context_dependent: number, reopened: number }} contradictions
|
|
71
|
-
* @property {string | null} lastConsolidation
|
|
72
|
-
* @property {number} totalConsolidationRuns
|
|
73
|
-
*
|
|
74
|
-
* @typedef {Object} TruthResolution
|
|
75
|
-
* @property {'a_wins' | 'b_wins' | 'context_dependent'} resolution
|
|
76
|
-
* @property {Object} [conditions]
|
|
77
|
-
* @property {string} explanation
|
|
78
|
-
*
|
|
79
|
-
* @typedef {Object} AudreyConfig
|
|
80
|
-
* @property {string} [dataDir]
|
|
81
|
-
* @property {string} [agent]
|
|
82
|
-
* @property {{ provider: 'mock' | 'openai', dimensions?: number, apiKey?: string }} [embedding]
|
|
83
|
-
* @property {{ provider: 'mock' | 'anthropic' | 'openai', apiKey?: string, model?: string }} [llm]
|
|
84
|
-
* @property {{ minEpisodes?: number }} [consolidation]
|
|
85
|
-
* @property {{ dormantThreshold?: number }} [decay]
|
|
86
|
-
*/
|
|
87
|
-
|
|
88
|
-
export class Audrey extends EventEmitter {
|
|
89
|
-
/** @param {AudreyConfig} [config] */
|
|
90
|
-
constructor({
|
|
91
|
-
dataDir = './audrey-data',
|
|
92
|
-
agent = 'default',
|
|
93
|
-
embedding = { provider: 'mock', dimensions: 64 },
|
|
94
|
-
llm,
|
|
95
|
-
confidence = {},
|
|
96
|
-
consolidation = {},
|
|
97
|
-
decay = {},
|
|
98
|
-
interference = {},
|
|
99
|
-
context = {},
|
|
100
|
-
affect = {},
|
|
101
|
-
autoReflect = false,
|
|
102
|
-
} = {}) {
|
|
103
|
-
super();
|
|
104
|
-
|
|
105
|
-
const dormantThreshold = decay.dormantThreshold ?? 0.1;
|
|
106
|
-
if (dormantThreshold < 0 || dormantThreshold > 1) {
|
|
107
|
-
throw new Error(`dormantThreshold must be between 0 and 1, got: ${dormantThreshold}`);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const minEpisodes = consolidation.minEpisodes ?? 3;
|
|
111
|
-
if (!Number.isInteger(minEpisodes) || minEpisodes < 1) {
|
|
112
|
-
throw new Error(`minEpisodes must be a positive integer, got: ${minEpisodes}`);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
this.agent = agent;
|
|
116
|
-
this.dataDir = dataDir;
|
|
117
|
-
this.embeddingProvider = createEmbeddingProvider(embedding);
|
|
118
|
-
const { db, migrated } = createDatabase(dataDir, { dimensions: this.embeddingProvider.dimensions });
|
|
119
|
-
this.db = db;
|
|
120
|
-
this._migrationPending = migrated;
|
|
121
|
-
this.llmProvider = llm ? createLLMProvider(llm) : null;
|
|
122
|
-
this.confidenceConfig = {
|
|
123
|
-
weights: confidence.weights,
|
|
124
|
-
halfLives: confidence.halfLives,
|
|
125
|
-
sourceReliability: confidence.sourceReliability,
|
|
126
|
-
interferenceWeight: interference.weight ?? 0.1,
|
|
127
|
-
contextWeight: context.weight ?? 0.3,
|
|
128
|
-
affectWeight: affect.weight ?? 0.2,
|
|
129
|
-
};
|
|
130
|
-
this.consolidationConfig = {
|
|
131
|
-
minEpisodes: consolidation.minEpisodes || 3,
|
|
132
|
-
};
|
|
133
|
-
this.decayConfig = { dormantThreshold: decay.dormantThreshold || 0.1 };
|
|
134
|
-
this._autoConsolidateTimer = null;
|
|
135
|
-
this.interferenceConfig = {
|
|
136
|
-
enabled: interference.enabled ?? true,
|
|
137
|
-
k: interference.k ?? 5,
|
|
138
|
-
threshold: interference.threshold ?? 0.6,
|
|
139
|
-
weight: interference.weight ?? 0.1,
|
|
140
|
-
};
|
|
141
|
-
this.contextConfig = {
|
|
142
|
-
enabled: context.enabled ?? true,
|
|
143
|
-
weight: context.weight ?? 0.3,
|
|
144
|
-
};
|
|
145
|
-
this.affectConfig = {
|
|
146
|
-
enabled: affect.enabled ?? true,
|
|
147
|
-
weight: affect.weight ?? 0.2,
|
|
148
|
-
arousalWeight: affect.arousalWeight ?? 0.3,
|
|
149
|
-
resonance: {
|
|
150
|
-
enabled: affect.resonance?.enabled ?? true,
|
|
151
|
-
k: affect.resonance?.k ?? 5,
|
|
152
|
-
threshold: affect.resonance?.threshold ?? 0.5,
|
|
153
|
-
affectThreshold: affect.resonance?.affectThreshold ?? 0.6,
|
|
154
|
-
},
|
|
155
|
-
};
|
|
156
|
-
this.autoReflect = autoReflect;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
async _ensureMigrated() {
|
|
160
|
-
if (!this._migrationPending) return;
|
|
161
|
-
const counts = await reembedAll(this.db, this.embeddingProvider);
|
|
162
|
-
this._migrationPending = false;
|
|
163
|
-
this.emit('migration', counts);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
_emitValidation(id, params) {
|
|
167
|
-
validateMemory(this.db, this.embeddingProvider, { id, ...params }, {
|
|
168
|
-
llmProvider: this.llmProvider,
|
|
169
|
-
})
|
|
170
|
-
.then(validation => {
|
|
171
|
-
if (validation.action === 'reinforced') {
|
|
172
|
-
this.emit('reinforcement', {
|
|
173
|
-
episodeId: id,
|
|
174
|
-
targetId: validation.semanticId,
|
|
175
|
-
similarity: validation.similarity,
|
|
176
|
-
});
|
|
177
|
-
} else if (validation.action === 'contradiction') {
|
|
178
|
-
this.emit('contradiction', {
|
|
179
|
-
episodeId: id,
|
|
180
|
-
contradictionId: validation.contradictionId,
|
|
181
|
-
semanticId: validation.semanticId,
|
|
182
|
-
similarity: validation.similarity,
|
|
183
|
-
resolution: validation.resolution,
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
})
|
|
187
|
-
.catch(err => this.emit('error', err));
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* @param {EncodeParams} params
|
|
192
|
-
* @returns {Promise<string>}
|
|
193
|
-
*/
|
|
194
|
-
async encode(params) {
|
|
195
|
-
await this._ensureMigrated();
|
|
196
|
-
const encodeParams = { ...params, arousalWeight: this.affectConfig.arousalWeight };
|
|
197
|
-
const id = await encodeEpisode(this.db, this.embeddingProvider, encodeParams);
|
|
198
|
-
this.emit('encode', { id, ...params });
|
|
199
|
-
if (this.interferenceConfig.enabled) {
|
|
200
|
-
applyInterference(this.db, this.embeddingProvider, id, params, this.interferenceConfig)
|
|
201
|
-
.then(affected => {
|
|
202
|
-
if (affected.length > 0) {
|
|
203
|
-
this.emit('interference', { episodeId: id, affected });
|
|
204
|
-
}
|
|
205
|
-
})
|
|
206
|
-
.catch(err => this.emit('error', err));
|
|
207
|
-
}
|
|
208
|
-
if (this.affectConfig.enabled && this.affectConfig.resonance.enabled && params.affect?.valence !== undefined) {
|
|
209
|
-
detectResonance(this.db, this.embeddingProvider, id, params, this.affectConfig.resonance)
|
|
210
|
-
.then(echoes => {
|
|
211
|
-
if (echoes.length > 0) {
|
|
212
|
-
this.emit('resonance', { episodeId: id, affect: params.affect, echoes });
|
|
213
|
-
}
|
|
214
|
-
})
|
|
215
|
-
.catch(err => this.emit('error', err));
|
|
216
|
-
}
|
|
217
|
-
this._emitValidation(id, params);
|
|
218
|
-
return id;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
async reflect(turns) {
|
|
223
|
-
if (!this.llmProvider) return { encoded: 0, memories: [], skipped: 'no llm provider' };
|
|
224
|
-
|
|
225
|
-
const prompt = buildReflectionPrompt(turns);
|
|
226
|
-
let raw;
|
|
227
|
-
try {
|
|
228
|
-
raw = await this.llmProvider.chat(prompt);
|
|
229
|
-
} catch (err) {
|
|
230
|
-
this.emit('error', err);
|
|
231
|
-
return { encoded: 0, memories: [], skipped: 'llm error' };
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
let parsed;
|
|
235
|
-
try {
|
|
236
|
-
parsed = JSON.parse(raw);
|
|
237
|
-
} catch {
|
|
238
|
-
return { encoded: 0, memories: [], skipped: 'invalid llm response' };
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
const memories = parsed.memories ?? [];
|
|
242
|
-
let encoded = 0;
|
|
243
|
-
for (const mem of memories) {
|
|
244
|
-
if (!mem.content || !mem.source) continue;
|
|
245
|
-
try {
|
|
246
|
-
await this.encode({
|
|
247
|
-
content: mem.content,
|
|
248
|
-
source: mem.source,
|
|
249
|
-
salience: mem.salience,
|
|
250
|
-
tags: mem.tags,
|
|
251
|
-
private: mem.private ?? false,
|
|
252
|
-
affect: mem.affect ?? undefined,
|
|
253
|
-
});
|
|
254
|
-
encoded++;
|
|
255
|
-
} catch (err) {
|
|
256
|
-
this.emit('error', err);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return { encoded, memories };
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* @param {EncodeParams[]} paramsList
|
|
265
|
-
* @returns {Promise<string[]>}
|
|
266
|
-
*/
|
|
267
|
-
async encodeBatch(paramsList) {
|
|
268
|
-
await this._ensureMigrated();
|
|
269
|
-
const ids = [];
|
|
270
|
-
for (const params of paramsList) {
|
|
271
|
-
const id = await encodeEpisode(this.db, this.embeddingProvider, params);
|
|
272
|
-
ids.push(id);
|
|
273
|
-
this.emit('encode', { id, ...params });
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
for (let i = 0; i < ids.length; i++) {
|
|
277
|
-
this._emitValidation(ids[i], paramsList[i]);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
return ids;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* @param {string} query
|
|
285
|
-
* @param {RecallOptions} [options]
|
|
286
|
-
* @returns {Promise<RecallResult[]>}
|
|
287
|
-
*/
|
|
288
|
-
async recall(query, options = {}) {
|
|
289
|
-
await this._ensureMigrated();
|
|
290
|
-
return recallFn(this.db, this.embeddingProvider, query, {
|
|
291
|
-
...options,
|
|
292
|
-
confidenceConfig: this._recallConfig(options),
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* @param {string} query
|
|
298
|
-
* @param {RecallOptions} [options]
|
|
299
|
-
* @returns {AsyncGenerator<RecallResult>}
|
|
300
|
-
*/
|
|
301
|
-
async *recallStream(query, options = {}) {
|
|
302
|
-
await this._ensureMigrated();
|
|
303
|
-
yield* recallStreamFn(this.db, this.embeddingProvider, query, {
|
|
304
|
-
...options,
|
|
305
|
-
confidenceConfig: this._recallConfig(options),
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
_recallConfig(options) {
|
|
310
|
-
let config = options.confidenceConfig ?? this.confidenceConfig;
|
|
311
|
-
if (this.contextConfig.enabled && options.context) {
|
|
312
|
-
config = { ...config, retrievalContext: options.context };
|
|
313
|
-
}
|
|
314
|
-
if (this.affectConfig.enabled && options.mood) {
|
|
315
|
-
config = { ...config, retrievalMood: options.mood };
|
|
316
|
-
}
|
|
317
|
-
return config;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* @param {{ minClusterSize?: number, similarityThreshold?: number, extractPrinciple?: Function, llmProvider?: import('./llm.js').LLMProvider }} [options]
|
|
322
|
-
* @returns {Promise<ConsolidationResult>}
|
|
323
|
-
*/
|
|
324
|
-
async consolidate(options = {}) {
|
|
325
|
-
await this._ensureMigrated();
|
|
326
|
-
const result = await runConsolidation(this.db, this.embeddingProvider, {
|
|
327
|
-
minClusterSize: options.minClusterSize || this.consolidationConfig.minEpisodes,
|
|
328
|
-
similarityThreshold: options.similarityThreshold || 0.80,
|
|
329
|
-
extractPrinciple: options.extractPrinciple,
|
|
330
|
-
llmProvider: options.llmProvider || this.llmProvider,
|
|
331
|
-
});
|
|
332
|
-
const run = this.db.prepare('SELECT status FROM consolidation_runs WHERE id = ?').get(result.runId);
|
|
333
|
-
const output = { ...result, status: run?.status || 'completed' };
|
|
334
|
-
this.emit('consolidation', output);
|
|
335
|
-
return output;
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
/**
|
|
339
|
-
* @param {{ dormantThreshold?: number }} [options]
|
|
340
|
-
* @returns {{ totalEvaluated: number, transitionedToDormant: number, timestamp: string }}
|
|
341
|
-
*/
|
|
342
|
-
decay(options = {}) {
|
|
343
|
-
const result = applyDecay(this.db, {
|
|
344
|
-
dormantThreshold: options.dormantThreshold || this.decayConfig.dormantThreshold,
|
|
345
|
-
halfLives: options.halfLives ?? this.confidenceConfig.halfLives,
|
|
346
|
-
});
|
|
347
|
-
this.emit('decay', result);
|
|
348
|
-
return result;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* @param {string} runId
|
|
353
|
-
* @returns {{ rolledBackMemories: number, restoredEpisodes: number }}
|
|
354
|
-
*/
|
|
355
|
-
rollback(runId) {
|
|
356
|
-
const result = rollbackConsolidation(this.db, runId);
|
|
357
|
-
this.emit('rollback', { runId, ...result });
|
|
358
|
-
return result;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* @param {string} contradictionId
|
|
363
|
-
* @returns {Promise<TruthResolution>}
|
|
364
|
-
*/
|
|
365
|
-
async resolveTruth(contradictionId) {
|
|
366
|
-
if (!this.llmProvider) {
|
|
367
|
-
throw new Error('resolveTruth requires an LLM provider');
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
const contradiction = this.db.prepare(
|
|
371
|
-
'SELECT * FROM contradictions WHERE id = ?'
|
|
372
|
-
).get(contradictionId);
|
|
373
|
-
if (!contradiction) throw new Error(`Contradiction not found: ${contradictionId}`);
|
|
374
|
-
|
|
375
|
-
const claimA = this._loadClaimContent(contradiction.claim_a_id, contradiction.claim_a_type);
|
|
376
|
-
const claimB = this._loadClaimContent(contradiction.claim_b_id, contradiction.claim_b_type);
|
|
377
|
-
|
|
378
|
-
const messages = buildContextResolutionPrompt(claimA, claimB);
|
|
379
|
-
const result = await this.llmProvider.json(messages);
|
|
380
|
-
|
|
381
|
-
const now = new Date().toISOString();
|
|
382
|
-
const newState = result.resolution === 'context_dependent' ? 'context_dependent' : 'resolved';
|
|
383
|
-
this.db.prepare(`
|
|
384
|
-
UPDATE contradictions SET state = ?, resolution = ?, resolved_at = ?
|
|
385
|
-
WHERE id = ?
|
|
386
|
-
`).run(newState, JSON.stringify(result), now, contradictionId);
|
|
387
|
-
|
|
388
|
-
if (result.resolution === 'a_wins' && contradiction.claim_a_type === 'semantic') {
|
|
389
|
-
this.db.prepare("UPDATE semantics SET state = 'active' WHERE id = ?").run(contradiction.claim_a_id);
|
|
390
|
-
}
|
|
391
|
-
if (result.resolution === 'b_wins' && contradiction.claim_b_type === 'semantic') {
|
|
392
|
-
this.db.prepare("UPDATE semantics SET state = 'active' WHERE id = ?").run(contradiction.claim_b_id);
|
|
393
|
-
}
|
|
394
|
-
if (result.resolution === 'context_dependent') {
|
|
395
|
-
if (contradiction.claim_a_type === 'semantic' && result.conditions) {
|
|
396
|
-
this.db.prepare("UPDATE semantics SET state = 'context_dependent', conditions = ? WHERE id = ?")
|
|
397
|
-
.run(JSON.stringify(result.conditions), contradiction.claim_a_id);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
return result;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
_loadClaimContent(claimId, claimType) {
|
|
405
|
-
if (claimType === 'semantic') {
|
|
406
|
-
const row = this.db.prepare('SELECT content FROM semantics WHERE id = ?').get(claimId);
|
|
407
|
-
if (!row) throw new Error(`Semantic memory not found: ${claimId}`);
|
|
408
|
-
return row.content;
|
|
409
|
-
} else if (claimType === 'episodic') {
|
|
410
|
-
const row = this.db.prepare('SELECT content FROM episodes WHERE id = ?').get(claimId);
|
|
411
|
-
if (!row) throw new Error(`Episode not found: ${claimId}`);
|
|
412
|
-
return row.content;
|
|
413
|
-
}
|
|
414
|
-
throw new Error(`Unknown claim type: ${claimType}`);
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
/** @returns {Array<{ id: string, input_episode_ids: string, output_memory_ids: string, started_at: string, completed_at: string, status: string }>} */
|
|
418
|
-
consolidationHistory() {
|
|
419
|
-
return getConsolidationHistory(this.db);
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
/** @returns {IntrospectResult} */
|
|
423
|
-
introspect() {
|
|
424
|
-
return introspectFn(this.db);
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
memoryStatus() {
|
|
428
|
-
const episodes = this.db.prepare('SELECT COUNT(*) as c FROM episodes').get().c;
|
|
429
|
-
const semantics = this.db.prepare('SELECT COUNT(*) as c FROM semantics').get().c;
|
|
430
|
-
const procedures = this.db.prepare('SELECT COUNT(*) as c FROM procedures').get().c;
|
|
431
|
-
const searchableEpisodes = this.db.prepare('SELECT COUNT(*) as c FROM episodes WHERE embedding IS NOT NULL').get().c;
|
|
432
|
-
const searchableSemantics = this.db.prepare('SELECT COUNT(*) as c FROM semantics WHERE embedding IS NOT NULL').get().c;
|
|
433
|
-
const searchableProcedures = this.db.prepare('SELECT COUNT(*) as c FROM procedures WHERE embedding IS NOT NULL').get().c;
|
|
434
|
-
|
|
435
|
-
let vecEpisodes = 0, vecSemantics = 0, vecProcedures = 0;
|
|
436
|
-
try {
|
|
437
|
-
vecEpisodes = this.db.prepare('SELECT COUNT(*) as c FROM vec_episodes').get().c;
|
|
438
|
-
vecSemantics = this.db.prepare('SELECT COUNT(*) as c FROM vec_semantics').get().c;
|
|
439
|
-
vecProcedures = this.db.prepare('SELECT COUNT(*) as c FROM vec_procedures').get().c;
|
|
440
|
-
} catch {
|
|
441
|
-
// vec tables may not exist if no dimensions configured
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
const dimsRow = this.db.prepare("SELECT value FROM audrey_config WHERE key = 'dimensions'").get();
|
|
445
|
-
const dimensions = dimsRow ? parseInt(dimsRow.value, 10) : null;
|
|
446
|
-
const versionRow = this.db.prepare("SELECT value FROM audrey_config WHERE key = 'schema_version'").get();
|
|
447
|
-
const schemaVersion = versionRow ? parseInt(versionRow.value, 10) : 0;
|
|
448
|
-
|
|
449
|
-
const device = this.embeddingProvider._actualDevice
|
|
450
|
-
?? this.embeddingProvider.device
|
|
451
|
-
?? null;
|
|
452
|
-
|
|
453
|
-
const healthy = episodes === vecEpisodes
|
|
454
|
-
&& semantics === vecSemantics
|
|
455
|
-
&& procedures === vecProcedures;
|
|
456
|
-
const reembedRecommended = searchableEpisodes !== vecEpisodes
|
|
457
|
-
|| searchableSemantics !== vecSemantics
|
|
458
|
-
|| searchableProcedures !== vecProcedures;
|
|
459
|
-
|
|
460
|
-
return {
|
|
461
|
-
episodes,
|
|
462
|
-
vec_episodes: vecEpisodes,
|
|
463
|
-
semantics,
|
|
464
|
-
vec_semantics: vecSemantics,
|
|
465
|
-
procedures,
|
|
466
|
-
vec_procedures: vecProcedures,
|
|
467
|
-
searchable_episodes: searchableEpisodes,
|
|
468
|
-
searchable_semantics: searchableSemantics,
|
|
469
|
-
searchable_procedures: searchableProcedures,
|
|
470
|
-
dimensions,
|
|
471
|
-
schema_version: schemaVersion,
|
|
472
|
-
device,
|
|
473
|
-
healthy,
|
|
474
|
-
reembed_recommended: reembedRecommended,
|
|
475
|
-
};
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
async greeting({ context, recentLimit = 10, principleLimit = 5, identityLimit = 5 } = {}) {
|
|
479
|
-
const recent = this.db.prepare(
|
|
480
|
-
'SELECT id, content, source, tags, salience, created_at FROM episodes WHERE "private" = 0 ORDER BY created_at DESC LIMIT ?'
|
|
481
|
-
).all(recentLimit);
|
|
482
|
-
|
|
483
|
-
const principles = this.db.prepare(
|
|
484
|
-
'SELECT id, content, salience, created_at FROM semantics WHERE state = ? ORDER BY salience DESC LIMIT ?'
|
|
485
|
-
).all('active', principleLimit);
|
|
486
|
-
|
|
487
|
-
const identity = this.db.prepare(
|
|
488
|
-
'SELECT id, content, tags, salience, created_at FROM episodes WHERE "private" = 1 ORDER BY created_at DESC LIMIT ?'
|
|
489
|
-
).all(identityLimit);
|
|
490
|
-
|
|
491
|
-
const unresolved = this.db.prepare(
|
|
492
|
-
"SELECT id, content, tags, salience, created_at FROM episodes WHERE tags LIKE '%unresolved%' AND salience > 0.3 ORDER BY created_at DESC LIMIT 10"
|
|
493
|
-
).all();
|
|
494
|
-
|
|
495
|
-
const rawAffectRows = this.db.prepare(
|
|
496
|
-
"SELECT affect FROM episodes WHERE affect IS NOT NULL AND affect != '{}' ORDER BY created_at DESC LIMIT 20"
|
|
497
|
-
).all();
|
|
498
|
-
|
|
499
|
-
const affectParsed = rawAffectRows
|
|
500
|
-
.map(r => { try { return JSON.parse(r.affect); } catch { return null; } })
|
|
501
|
-
.filter(a => a && a.valence !== undefined);
|
|
502
|
-
|
|
503
|
-
let mood;
|
|
504
|
-
if (affectParsed.length === 0) {
|
|
505
|
-
mood = { valence: 0, arousal: 0, samples: 0 };
|
|
506
|
-
} else {
|
|
507
|
-
const sumV = affectParsed.reduce((s, a) => s + a.valence, 0);
|
|
508
|
-
const sumA = affectParsed.reduce((s, a) => s + (a.arousal ?? 0), 0);
|
|
509
|
-
mood = {
|
|
510
|
-
valence: sumV / affectParsed.length,
|
|
511
|
-
arousal: sumA / affectParsed.length,
|
|
512
|
-
samples: affectParsed.length,
|
|
513
|
-
};
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
const result = { recent, principles, mood, unresolved, identity };
|
|
517
|
-
|
|
518
|
-
if (context) {
|
|
519
|
-
result.contextual = await this.recall(context, { limit: 5, includePrivate: true });
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
return result;
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
async dream(options = {}) {
|
|
526
|
-
await this._ensureMigrated();
|
|
527
|
-
|
|
528
|
-
const consolidation = await this.consolidate({
|
|
529
|
-
minClusterSize: options.minClusterSize,
|
|
530
|
-
similarityThreshold: options.similarityThreshold,
|
|
531
|
-
});
|
|
532
|
-
|
|
533
|
-
const decay = this.decay({
|
|
534
|
-
dormantThreshold: options.dormantThreshold,
|
|
535
|
-
});
|
|
536
|
-
|
|
537
|
-
const stats = this.introspect();
|
|
538
|
-
|
|
539
|
-
const result = {
|
|
540
|
-
consolidation,
|
|
541
|
-
decay,
|
|
542
|
-
stats,
|
|
543
|
-
};
|
|
544
|
-
|
|
545
|
-
this.emit('dream', result);
|
|
546
|
-
return result;
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
export() {
|
|
550
|
-
return exportMemories(this.db);
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
async import(snapshot) {
|
|
554
|
-
return importMemories(this.db, this.embeddingProvider, snapshot);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
startAutoConsolidate(intervalMs, options = {}) {
|
|
558
|
-
if (intervalMs < 1000) {
|
|
559
|
-
throw new Error('Auto-consolidation interval must be at least 1000ms');
|
|
560
|
-
}
|
|
561
|
-
if (this._autoConsolidateTimer) {
|
|
562
|
-
throw new Error('Auto-consolidation is already running');
|
|
563
|
-
}
|
|
564
|
-
this._autoConsolidateTimer = setInterval(() => {
|
|
565
|
-
this.consolidate(options).catch(err => this.emit('error', err));
|
|
566
|
-
}, intervalMs);
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
stopAutoConsolidate() {
|
|
570
|
-
if (this._autoConsolidateTimer) {
|
|
571
|
-
clearInterval(this._autoConsolidateTimer);
|
|
572
|
-
this._autoConsolidateTimer = null;
|
|
573
|
-
}
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
suggestConsolidationParams() {
|
|
577
|
-
return suggestParamsFn(this.db);
|
|
578
|
-
}
|
|
579
|
-
|
|
580
|
-
forget(id, options = {}) {
|
|
581
|
-
const result = forgetMemory(this.db, id, options);
|
|
582
|
-
this.emit('forget', result);
|
|
583
|
-
return result;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
async forgetByQuery(query, options = {}) {
|
|
587
|
-
await this._ensureMigrated();
|
|
588
|
-
const result = await forgetByQueryFn(this.db, this.embeddingProvider, query, options);
|
|
589
|
-
if (result) this.emit('forget', result);
|
|
590
|
-
return result;
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
purge() {
|
|
594
|
-
const result = purgeMemories(this.db);
|
|
595
|
-
this.emit('purge', result);
|
|
596
|
-
return result;
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
/** @returns {void} */
|
|
600
|
-
close() {
|
|
601
|
-
this.stopAutoConsolidate();
|
|
602
|
-
closeDatabase(this.db);
|
|
603
|
-
}
|
|
604
|
-
}
|
package/src/causal.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { generateId } from './ulid.js';
|
|
2
|
-
import { buildCausalArticulationPrompt } from './prompts.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* @param {import('better-sqlite3').Database} db
|
|
6
|
-
* @param {{ causeId: string, effectId: string, linkType?: string, mechanism?: string, confidence?: number }} params
|
|
7
|
-
* @returns {string}
|
|
8
|
-
*/
|
|
9
|
-
export function addCausalLink(db, { causeId, effectId, linkType = 'causal', mechanism, confidence }) {
|
|
10
|
-
const id = generateId();
|
|
11
|
-
const now = new Date().toISOString();
|
|
12
|
-
|
|
13
|
-
db.prepare(`
|
|
14
|
-
INSERT INTO causal_links (id, cause_id, effect_id, link_type, mechanism, confidence, created_at)
|
|
15
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
16
|
-
`).run(id, causeId, effectId, linkType, mechanism, confidence, now);
|
|
17
|
-
|
|
18
|
-
return id;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @param {import('better-sqlite3').Database} db
|
|
23
|
-
* @param {string} memoryId
|
|
24
|
-
* @param {{ depth?: number }} [options]
|
|
25
|
-
* @returns {Object[]}
|
|
26
|
-
*/
|
|
27
|
-
export function getCausalChain(db, memoryId, options = {}) {
|
|
28
|
-
const { depth = 10 } = options;
|
|
29
|
-
const results = [];
|
|
30
|
-
const visited = new Set();
|
|
31
|
-
const queue = [memoryId];
|
|
32
|
-
let currentDepth = 0;
|
|
33
|
-
|
|
34
|
-
while (queue.length > 0 && currentDepth < depth) {
|
|
35
|
-
const nextQueue = [];
|
|
36
|
-
for (const nodeId of queue) {
|
|
37
|
-
if (visited.has(nodeId)) continue;
|
|
38
|
-
visited.add(nodeId);
|
|
39
|
-
|
|
40
|
-
const links = db.prepare(
|
|
41
|
-
'SELECT * FROM causal_links WHERE cause_id = ?'
|
|
42
|
-
).all(nodeId);
|
|
43
|
-
|
|
44
|
-
for (const link of links) {
|
|
45
|
-
if (!visited.has(link.effect_id)) {
|
|
46
|
-
results.push(link);
|
|
47
|
-
nextQueue.push(link.effect_id);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
queue.length = 0;
|
|
52
|
-
queue.push(...nextQueue);
|
|
53
|
-
currentDepth++;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return results;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* @param {import('better-sqlite3').Database} db
|
|
61
|
-
* @param {import('./llm.js').LLMProvider} llmProvider
|
|
62
|
-
* @param {{ id: string, content: string, source: string }} cause
|
|
63
|
-
* @param {{ id: string, content: string, source: string }} effect
|
|
64
|
-
* @returns {Promise<{ linkId: string|null, mechanism: string, linkType: string, confidence: number, spurious: boolean }>}
|
|
65
|
-
*/
|
|
66
|
-
export async function articulateCausalLink(db, llmProvider, cause, effect) {
|
|
67
|
-
const messages = buildCausalArticulationPrompt(cause, effect);
|
|
68
|
-
const result = await llmProvider.json(messages);
|
|
69
|
-
|
|
70
|
-
if (result.spurious) {
|
|
71
|
-
return {
|
|
72
|
-
linkId: null,
|
|
73
|
-
mechanism: result.mechanism,
|
|
74
|
-
linkType: result.linkType,
|
|
75
|
-
confidence: result.confidence,
|
|
76
|
-
spurious: true,
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const linkId = addCausalLink(db, {
|
|
81
|
-
causeId: cause.id,
|
|
82
|
-
effectId: effect.id,
|
|
83
|
-
linkType: result.linkType || 'correlational',
|
|
84
|
-
mechanism: result.mechanism,
|
|
85
|
-
confidence: result.confidence,
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
return {
|
|
89
|
-
linkId,
|
|
90
|
-
mechanism: result.mechanism,
|
|
91
|
-
linkType: result.linkType,
|
|
92
|
-
confidence: result.confidence,
|
|
93
|
-
spurious: false,
|
|
94
|
-
};
|
|
95
|
-
}
|