audrey 0.14.0 → 0.16.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 +808 -681
- package/mcp-server/config.js +76 -76
- package/mcp-server/index.js +728 -437
- package/package.json +76 -77
- package/src/adaptive.js +53 -53
- package/src/affect.js +64 -64
- package/src/audrey.js +604 -570
- package/src/causal.js +95 -95
- package/src/confidence.js +120 -120
- package/src/consolidate.js +265 -242
- package/src/context.js +15 -15
- package/src/db.js +37 -0
- package/src/decay.js +84 -84
- package/src/embedding.js +256 -256
- package/src/export.js +67 -61
- package/src/forget.js +111 -111
- package/src/import.js +245 -123
- package/src/index.js +27 -20
- package/src/interference.js +51 -51
- package/src/introspect.js +48 -48
- package/src/llm.js +246 -240
- package/src/migrate.js +58 -58
- package/src/prompts.js +223 -223
- package/src/recall.js +352 -329
- package/src/rollback.js +42 -42
- package/src/ulid.js +18 -18
- package/src/utils.js +38 -38
- package/src/validate.js +172 -172
package/src/llm.js
CHANGED
|
@@ -1,240 +1,246 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @typedef {Object} ChatMessage
|
|
3
|
-
* @property {'system' | 'user' | 'assistant'} role
|
|
4
|
-
* @property {string} content
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @typedef {Object}
|
|
14
|
-
* @property {
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @typedef {Object}
|
|
19
|
-
* @property {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
* @
|
|
27
|
-
* @property {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
* @
|
|
33
|
-
* @property {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
* @
|
|
41
|
-
* @property {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
this.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {Object} ChatMessage
|
|
3
|
+
* @property {'system' | 'user' | 'assistant'} role
|
|
4
|
+
* @property {string} content
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
function extractJSON(text) {
|
|
8
|
+
const fenced = text.match(/```(?:json)?\s*\n?([\s\S]*?)```/);
|
|
9
|
+
return fenced ? fenced[1].trim() : text.trim();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @typedef {Object} LLMCompletionResult
|
|
14
|
+
* @property {string} content
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @typedef {Object} LLMCompletionOptions
|
|
19
|
+
* @property {number} [maxTokens]
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @typedef {Object} LLMProvider
|
|
24
|
+
* @property {string} modelName
|
|
25
|
+
* @property {string} modelVersion
|
|
26
|
+
* @property {(messages: ChatMessage[], options?: LLMCompletionOptions) => Promise<LLMCompletionResult>} complete
|
|
27
|
+
* @property {(messages: ChatMessage[], options?: LLMCompletionOptions) => Promise<Object>} json
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @typedef {Object} MockLLMConfig
|
|
32
|
+
* @property {'mock'} provider
|
|
33
|
+
* @property {Record<string, Object>} [responses={}]
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* @typedef {Object} AnthropicLLMConfig
|
|
38
|
+
* @property {'anthropic'} provider
|
|
39
|
+
* @property {string} [apiKey]
|
|
40
|
+
* @property {string} [model='claude-sonnet-4-6']
|
|
41
|
+
* @property {number} [maxTokens=1024]
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* @typedef {Object} OpenAILLMConfig
|
|
46
|
+
* @property {'openai'} provider
|
|
47
|
+
* @property {string} [apiKey]
|
|
48
|
+
* @property {string} [model='gpt-4o']
|
|
49
|
+
* @property {number} [maxTokens=1024]
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
const PROMPT_TYPE_KEYS = [
|
|
53
|
+
'principleExtraction',
|
|
54
|
+
'contradictionDetection',
|
|
55
|
+
'causalArticulation',
|
|
56
|
+
'contextResolution',
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
/** @implements {LLMProvider} */
|
|
60
|
+
export class MockLLMProvider {
|
|
61
|
+
/** @param {Partial<MockLLMConfig>} [config={}] */
|
|
62
|
+
constructor({ responses = {} } = {}) {
|
|
63
|
+
this.responses = responses;
|
|
64
|
+
this.modelName = 'mock-llm';
|
|
65
|
+
this.modelVersion = '1.0.0';
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
_matchPromptType(messages) {
|
|
69
|
+
const systemMsg = messages.find(m => m.role === 'system')?.content || '';
|
|
70
|
+
for (const key of PROMPT_TYPE_KEYS) {
|
|
71
|
+
if (systemMsg.includes(key)) return key;
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @param {ChatMessage[]} messages
|
|
78
|
+
* @returns {Promise<LLMCompletionResult>}
|
|
79
|
+
*/
|
|
80
|
+
async complete(messages) {
|
|
81
|
+
const promptType = this._matchPromptType(messages);
|
|
82
|
+
const cannedResponse = promptType ? this.responses[promptType] : undefined;
|
|
83
|
+
return { content: cannedResponse !== undefined ? JSON.stringify(cannedResponse) : '{}' };
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @param {ChatMessage[]} messages
|
|
88
|
+
* @returns {Promise<Object>}
|
|
89
|
+
*/
|
|
90
|
+
async json(messages) {
|
|
91
|
+
const promptType = this._matchPromptType(messages);
|
|
92
|
+
const cannedResponse = promptType ? this.responses[promptType] : undefined;
|
|
93
|
+
return cannedResponse !== undefined ? cannedResponse : {};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** @implements {LLMProvider} */
|
|
98
|
+
export class AnthropicLLMProvider {
|
|
99
|
+
/** @param {Partial<AnthropicLLMConfig>} [config={}] */
|
|
100
|
+
constructor({ apiKey, model = 'claude-sonnet-4-6', maxTokens = 1024, timeout = 30000 } = {}) {
|
|
101
|
+
this.apiKey = apiKey || process.env.ANTHROPIC_API_KEY;
|
|
102
|
+
this.model = model;
|
|
103
|
+
this.maxTokens = maxTokens;
|
|
104
|
+
this.timeout = timeout;
|
|
105
|
+
this.modelName = model;
|
|
106
|
+
this.modelVersion = 'latest';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @param {ChatMessage[]} messages
|
|
111
|
+
* @param {LLMCompletionOptions} [options={}]
|
|
112
|
+
* @returns {Promise<LLMCompletionResult>}
|
|
113
|
+
*/
|
|
114
|
+
async complete(messages, options = {}) {
|
|
115
|
+
const systemMsg = messages.find(m => m.role === 'system')?.content;
|
|
116
|
+
const nonSystemMsgs = messages.filter(m => m.role !== 'system');
|
|
117
|
+
|
|
118
|
+
const body = {
|
|
119
|
+
model: this.model,
|
|
120
|
+
max_tokens: options.maxTokens || this.maxTokens,
|
|
121
|
+
messages: nonSystemMsgs,
|
|
122
|
+
};
|
|
123
|
+
if (systemMsg) body.system = systemMsg;
|
|
124
|
+
|
|
125
|
+
const controller = new AbortController();
|
|
126
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
127
|
+
try {
|
|
128
|
+
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
|
129
|
+
method: 'POST',
|
|
130
|
+
headers: {
|
|
131
|
+
'x-api-key': this.apiKey,
|
|
132
|
+
'anthropic-version': '2023-06-01',
|
|
133
|
+
'content-type': 'application/json',
|
|
134
|
+
},
|
|
135
|
+
body: JSON.stringify(body),
|
|
136
|
+
signal: controller.signal,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
if (!response.ok) {
|
|
140
|
+
const errorBody = await response.text().catch(() => '');
|
|
141
|
+
throw new Error(`Anthropic API error: ${response.status} ${errorBody}`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const data = await response.json();
|
|
145
|
+
const text = data.content?.[0]?.text || '';
|
|
146
|
+
return { content: text };
|
|
147
|
+
} finally {
|
|
148
|
+
clearTimeout(timer);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* @param {ChatMessage[]} messages
|
|
154
|
+
* @param {LLMCompletionOptions} [options={}]
|
|
155
|
+
* @returns {Promise<Object>}
|
|
156
|
+
*/
|
|
157
|
+
async json(messages, options = {}) {
|
|
158
|
+
const result = await this.complete(messages, options);
|
|
159
|
+
try {
|
|
160
|
+
return JSON.parse(extractJSON(result.content));
|
|
161
|
+
} catch {
|
|
162
|
+
throw new Error(`Failed to parse LLM response as JSON: ${result.content.slice(0, 200)}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** @implements {LLMProvider} */
|
|
168
|
+
export class OpenAILLMProvider {
|
|
169
|
+
/** @param {Partial<OpenAILLMConfig>} [config={}] */
|
|
170
|
+
constructor({ apiKey, model = 'gpt-4o', maxTokens = 1024, timeout = 30000 } = {}) {
|
|
171
|
+
this.apiKey = apiKey || process.env.OPENAI_API_KEY;
|
|
172
|
+
this.model = model;
|
|
173
|
+
this.maxTokens = maxTokens;
|
|
174
|
+
this.timeout = timeout;
|
|
175
|
+
this.modelName = model;
|
|
176
|
+
this.modelVersion = 'latest';
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* @param {ChatMessage[]} messages
|
|
181
|
+
* @param {LLMCompletionOptions} [options={}]
|
|
182
|
+
* @returns {Promise<LLMCompletionResult>}
|
|
183
|
+
*/
|
|
184
|
+
async complete(messages, options = {}) {
|
|
185
|
+
const body = {
|
|
186
|
+
model: this.model,
|
|
187
|
+
max_tokens: options.maxTokens || this.maxTokens,
|
|
188
|
+
messages,
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const controller = new AbortController();
|
|
192
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
193
|
+
try {
|
|
194
|
+
const response = await fetch('https://api.openai.com/v1/chat/completions', {
|
|
195
|
+
method: 'POST',
|
|
196
|
+
headers: {
|
|
197
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
198
|
+
'Content-Type': 'application/json',
|
|
199
|
+
},
|
|
200
|
+
body: JSON.stringify(body),
|
|
201
|
+
signal: controller.signal,
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
if (!response.ok) {
|
|
205
|
+
throw new Error(`OpenAI API error: ${response.status}`);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const data = await response.json();
|
|
209
|
+
const text = data.choices?.[0]?.message?.content || '';
|
|
210
|
+
return { content: text };
|
|
211
|
+
} finally {
|
|
212
|
+
clearTimeout(timer);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* @param {ChatMessage[]} messages
|
|
218
|
+
* @param {LLMCompletionOptions} [options={}]
|
|
219
|
+
* @returns {Promise<Object>}
|
|
220
|
+
*/
|
|
221
|
+
async json(messages, options = {}) {
|
|
222
|
+
const result = await this.complete(messages, options);
|
|
223
|
+
try {
|
|
224
|
+
return JSON.parse(extractJSON(result.content));
|
|
225
|
+
} catch {
|
|
226
|
+
throw new Error(`Failed to parse LLM response as JSON: ${result.content.slice(0, 200)}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* @param {MockLLMConfig | AnthropicLLMConfig | OpenAILLMConfig} config
|
|
233
|
+
* @returns {MockLLMProvider | AnthropicLLMProvider | OpenAILLMProvider}
|
|
234
|
+
*/
|
|
235
|
+
export function createLLMProvider(config) {
|
|
236
|
+
switch (config.provider) {
|
|
237
|
+
case 'mock':
|
|
238
|
+
return new MockLLMProvider(config);
|
|
239
|
+
case 'anthropic':
|
|
240
|
+
return new AnthropicLLMProvider(config);
|
|
241
|
+
case 'openai':
|
|
242
|
+
return new OpenAILLMProvider(config);
|
|
243
|
+
default:
|
|
244
|
+
throw new Error(`Unknown LLM provider: ${config.provider}. Valid: mock, anthropic, openai`);
|
|
245
|
+
}
|
|
246
|
+
}
|
package/src/migrate.js
CHANGED
|
@@ -1,58 +1,58 @@
|
|
|
1
|
-
import { dropVec0Tables, createVec0Tables } from './db.js';
|
|
2
|
-
|
|
3
|
-
export async function reembedAll(db, embeddingProvider, { dropAndRecreate = false } = {}) {
|
|
4
|
-
if (dropAndRecreate) {
|
|
5
|
-
dropVec0Tables(db);
|
|
6
|
-
createVec0Tables(db, embeddingProvider.dimensions);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const episodes = db.prepare('SELECT id, content, source FROM episodes').all();
|
|
10
|
-
const semantics = db.prepare('SELECT id, content, state FROM semantics').all();
|
|
11
|
-
const procedures = db.prepare('SELECT id, content, state FROM procedures').all();
|
|
12
|
-
|
|
13
|
-
const episodeVectors = episodes.length > 0
|
|
14
|
-
? await embeddingProvider.embedBatch(episodes.map(ep => ep.content))
|
|
15
|
-
: [];
|
|
16
|
-
const semanticVectors = semantics.length > 0
|
|
17
|
-
? await embeddingProvider.embedBatch(semantics.map(s => s.content))
|
|
18
|
-
: [];
|
|
19
|
-
const procedureVectors = procedures.length > 0
|
|
20
|
-
? await embeddingProvider.embedBatch(procedures.map(p => p.content))
|
|
21
|
-
: [];
|
|
22
|
-
|
|
23
|
-
const updateEpLegacy = db.prepare('UPDATE episodes SET embedding = ? WHERE id = ?');
|
|
24
|
-
const deleteVecEp = db.prepare('DELETE FROM vec_episodes WHERE id = ?');
|
|
25
|
-
const insertVecEp = db.prepare('INSERT INTO vec_episodes(id, embedding, source, consolidated) VALUES (?, ?, ?, ?)');
|
|
26
|
-
|
|
27
|
-
const updateSemLegacy = db.prepare('UPDATE semantics SET embedding = ? WHERE id = ?');
|
|
28
|
-
const deleteVecSem = db.prepare('DELETE FROM vec_semantics WHERE id = ?');
|
|
29
|
-
const insertVecSem = db.prepare('INSERT INTO vec_semantics(id, embedding, state) VALUES (?, ?, ?)');
|
|
30
|
-
|
|
31
|
-
const updateProcLegacy = db.prepare('UPDATE procedures SET embedding = ? WHERE id = ?');
|
|
32
|
-
const deleteVecProc = db.prepare('DELETE FROM vec_procedures WHERE id = ?');
|
|
33
|
-
const insertVecProc = db.prepare('INSERT INTO vec_procedures(id, embedding, state) VALUES (?, ?, ?)');
|
|
34
|
-
|
|
35
|
-
const writeTx = db.transaction(() => {
|
|
36
|
-
for (let i = 0; i < episodes.length; i++) {
|
|
37
|
-
const buf = embeddingProvider.vectorToBuffer(episodeVectors[i]);
|
|
38
|
-
updateEpLegacy.run(buf, episodes[i].id);
|
|
39
|
-
deleteVecEp.run(episodes[i].id);
|
|
40
|
-
insertVecEp.run(episodes[i].id, buf, episodes[i].source, BigInt(0));
|
|
41
|
-
}
|
|
42
|
-
for (let i = 0; i < semantics.length; i++) {
|
|
43
|
-
const buf = embeddingProvider.vectorToBuffer(semanticVectors[i]);
|
|
44
|
-
updateSemLegacy.run(buf, semantics[i].id);
|
|
45
|
-
deleteVecSem.run(semantics[i].id);
|
|
46
|
-
insertVecSem.run(semantics[i].id, buf, semantics[i].state);
|
|
47
|
-
}
|
|
48
|
-
for (let i = 0; i < procedures.length; i++) {
|
|
49
|
-
const buf = embeddingProvider.vectorToBuffer(procedureVectors[i]);
|
|
50
|
-
updateProcLegacy.run(buf, procedures[i].id);
|
|
51
|
-
deleteVecProc.run(procedures[i].id);
|
|
52
|
-
insertVecProc.run(procedures[i].id, buf, procedures[i].state);
|
|
53
|
-
}
|
|
54
|
-
});
|
|
55
|
-
writeTx();
|
|
56
|
-
|
|
57
|
-
return { episodes: episodes.length, semantics: semantics.length, procedures: procedures.length };
|
|
58
|
-
}
|
|
1
|
+
import { dropVec0Tables, createVec0Tables } from './db.js';
|
|
2
|
+
|
|
3
|
+
export async function reembedAll(db, embeddingProvider, { dropAndRecreate = false } = {}) {
|
|
4
|
+
if (dropAndRecreate) {
|
|
5
|
+
dropVec0Tables(db);
|
|
6
|
+
createVec0Tables(db, embeddingProvider.dimensions);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const episodes = db.prepare('SELECT id, content, source FROM episodes').all();
|
|
10
|
+
const semantics = db.prepare('SELECT id, content, state FROM semantics').all();
|
|
11
|
+
const procedures = db.prepare('SELECT id, content, state FROM procedures').all();
|
|
12
|
+
|
|
13
|
+
const episodeVectors = episodes.length > 0
|
|
14
|
+
? await embeddingProvider.embedBatch(episodes.map(ep => ep.content))
|
|
15
|
+
: [];
|
|
16
|
+
const semanticVectors = semantics.length > 0
|
|
17
|
+
? await embeddingProvider.embedBatch(semantics.map(s => s.content))
|
|
18
|
+
: [];
|
|
19
|
+
const procedureVectors = procedures.length > 0
|
|
20
|
+
? await embeddingProvider.embedBatch(procedures.map(p => p.content))
|
|
21
|
+
: [];
|
|
22
|
+
|
|
23
|
+
const updateEpLegacy = db.prepare('UPDATE episodes SET embedding = ? WHERE id = ?');
|
|
24
|
+
const deleteVecEp = db.prepare('DELETE FROM vec_episodes WHERE id = ?');
|
|
25
|
+
const insertVecEp = db.prepare('INSERT INTO vec_episodes(id, embedding, source, consolidated) VALUES (?, ?, ?, ?)');
|
|
26
|
+
|
|
27
|
+
const updateSemLegacy = db.prepare('UPDATE semantics SET embedding = ? WHERE id = ?');
|
|
28
|
+
const deleteVecSem = db.prepare('DELETE FROM vec_semantics WHERE id = ?');
|
|
29
|
+
const insertVecSem = db.prepare('INSERT INTO vec_semantics(id, embedding, state) VALUES (?, ?, ?)');
|
|
30
|
+
|
|
31
|
+
const updateProcLegacy = db.prepare('UPDATE procedures SET embedding = ? WHERE id = ?');
|
|
32
|
+
const deleteVecProc = db.prepare('DELETE FROM vec_procedures WHERE id = ?');
|
|
33
|
+
const insertVecProc = db.prepare('INSERT INTO vec_procedures(id, embedding, state) VALUES (?, ?, ?)');
|
|
34
|
+
|
|
35
|
+
const writeTx = db.transaction(() => {
|
|
36
|
+
for (let i = 0; i < episodes.length; i++) {
|
|
37
|
+
const buf = embeddingProvider.vectorToBuffer(episodeVectors[i]);
|
|
38
|
+
updateEpLegacy.run(buf, episodes[i].id);
|
|
39
|
+
deleteVecEp.run(episodes[i].id);
|
|
40
|
+
insertVecEp.run(episodes[i].id, buf, episodes[i].source, BigInt(0));
|
|
41
|
+
}
|
|
42
|
+
for (let i = 0; i < semantics.length; i++) {
|
|
43
|
+
const buf = embeddingProvider.vectorToBuffer(semanticVectors[i]);
|
|
44
|
+
updateSemLegacy.run(buf, semantics[i].id);
|
|
45
|
+
deleteVecSem.run(semantics[i].id);
|
|
46
|
+
insertVecSem.run(semantics[i].id, buf, semantics[i].state);
|
|
47
|
+
}
|
|
48
|
+
for (let i = 0; i < procedures.length; i++) {
|
|
49
|
+
const buf = embeddingProvider.vectorToBuffer(procedureVectors[i]);
|
|
50
|
+
updateProcLegacy.run(buf, procedures[i].id);
|
|
51
|
+
deleteVecProc.run(procedures[i].id);
|
|
52
|
+
insertVecProc.run(procedures[i].id, buf, procedures[i].state);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
writeTx();
|
|
56
|
+
|
|
57
|
+
return { episodes: episodes.length, semantics: semantics.length, procedures: procedures.length };
|
|
58
|
+
}
|