@tenphi/akno-core 0.13.0 → 0.13.2
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/dist/bench/language-corpus-v23.d.ts +4 -0
- package/dist/bench/language-corpus-v23.d.ts.map +1 -0
- package/dist/bench/language-corpus-v23.js +203 -0
- package/dist/bench/language-corpus-v23.js.map +1 -0
- package/dist/bench/language-review.d.ts +26 -0
- package/dist/bench/language-review.d.ts.map +1 -1
- package/dist/bench/language-review.js +15 -1
- package/dist/bench/language-review.js.map +1 -1
- package/dist/bench/language.d.ts +885 -27
- package/dist/bench/language.d.ts.map +1 -1
- package/dist/bench/language.js +94 -7
- package/dist/bench/language.js.map +1 -1
- package/dist/context.d.ts +3 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js.map +1 -1
- package/dist/index/indexer.d.ts +10 -0
- package/dist/index/indexer.d.ts.map +1 -1
- package/dist/index/indexer.js +21 -1
- package/dist/index/indexer.js.map +1 -1
- package/dist/kb/prose.d.ts +1 -1
- package/dist/kb/prose.d.ts.map +1 -1
- package/dist/kb/prose.js +120 -10
- package/dist/kb/prose.js.map +1 -1
- package/dist/maintenance/brain-migration.d.ts +4 -1
- package/dist/maintenance/brain-migration.d.ts.map +1 -1
- package/dist/maintenance/brain-migration.js +29 -6
- package/dist/maintenance/brain-migration.js.map +1 -1
- package/dist/maintenance/dream.d.ts +2 -0
- package/dist/maintenance/dream.d.ts.map +1 -1
- package/dist/maintenance/dream.js +270 -64
- package/dist/maintenance/dream.js.map +1 -1
- package/dist/maintenance/observation-scope.d.ts +74 -0
- package/dist/maintenance/observation-scope.d.ts.map +1 -0
- package/dist/maintenance/observation-scope.js +259 -0
- package/dist/maintenance/observation-scope.js.map +1 -0
- package/dist/maintenance/observe.d.ts +2 -0
- package/dist/maintenance/observe.d.ts.map +1 -1
- package/dist/maintenance/observe.js +28 -24
- package/dist/maintenance/observe.js.map +1 -1
- package/dist/maintenance/plans.d.ts +20 -1
- package/dist/maintenance/plans.d.ts.map +1 -1
- package/dist/maintenance/plans.js +251 -35
- package/dist/maintenance/plans.js.map +1 -1
- package/dist/memory/intent.d.ts +1 -1
- package/dist/memory/intent.d.ts.map +1 -1
- package/dist/memory/intent.js +49 -14
- package/dist/memory/intent.js.map +1 -1
- package/dist/observations/marker.d.ts +2 -0
- package/dist/observations/marker.d.ts.map +1 -1
- package/dist/observations/marker.js +16 -4
- package/dist/observations/marker.js.map +1 -1
- package/dist/observations/projection.d.ts +1 -1
- package/dist/observations/projection.d.ts.map +1 -1
- package/dist/observations/projection.js +14 -5
- package/dist/observations/projection.js.map +1 -1
- package/dist/open.d.ts.map +1 -1
- package/dist/open.js +5 -0
- package/dist/open.js.map +1 -1
- package/dist/ops/folder.d.ts.map +1 -1
- package/dist/ops/folder.js +3 -0
- package/dist/ops/folder.js.map +1 -1
- package/dist/ops/forget.d.ts.map +1 -1
- package/dist/ops/forget.js +9 -0
- package/dist/ops/forget.js.map +1 -1
- package/dist/ops/graph.js +5 -1
- package/dist/ops/graph.js.map +1 -1
- package/dist/ops/move.d.ts.map +1 -1
- package/dist/ops/move.js +15 -7
- package/dist/ops/move.js.map +1 -1
- package/dist/ops/remember.d.ts.map +1 -1
- package/dist/ops/remember.js +34 -8
- package/dist/ops/remember.js.map +1 -1
- package/dist/ops/retain.d.ts.map +1 -1
- package/dist/ops/retain.js +119 -2
- package/dist/ops/retain.js.map +1 -1
- package/dist/ops/write.d.ts.map +1 -1
- package/dist/ops/write.js +17 -4
- package/dist/ops/write.js.map +1 -1
- package/dist/store/db.d.ts.map +1 -1
- package/dist/store/db.js +18 -1
- package/dist/store/db.js.map +1 -1
- package/dist/store/migrations.d.ts +4 -2
- package/dist/store/migrations.d.ts.map +1 -1
- package/dist/store/migrations.js +41 -2
- package/dist/store/migrations.js.map +1 -1
- package/dist/write/journal.d.ts +2 -0
- package/dist/write/journal.d.ts.map +1 -1
- package/dist/write/journal.js +11 -0
- package/dist/write/journal.js.map +1 -1
- package/dist/write/mutation-receipts.d.ts +32 -0
- package/dist/write/mutation-receipts.d.ts.map +1 -0
- package/dist/write/mutation-receipts.js +331 -0
- package/dist/write/mutation-receipts.js.map +1 -0
- package/dist/write/retain.d.ts +6 -2
- package/dist/write/retain.d.ts.map +1 -1
- package/dist/write/retain.js +76 -9
- package/dist/write/retain.js.map +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { AknoError } from '@tenphi/akno-protocol';
|
|
3
|
+
import { sha256 } from "../store/ids.js";
|
|
4
|
+
import { normalizeSlug } from "../ops/write.js";
|
|
5
|
+
const REPLAY_SAFE_OPERATIONS = ['write', 'move', 'forget', 'folder'];
|
|
6
|
+
// A process can open the same knowledge base twice because its pid already owns the write lock.
|
|
7
|
+
// Key by database path as well as receipt identity so those handles still agree which call is live.
|
|
8
|
+
const activeReceipts = new Set();
|
|
9
|
+
const MAX_RESULT_BYTES = 64 * 1024;
|
|
10
|
+
export function isReplaySafeOperation(operation) {
|
|
11
|
+
return REPLAY_SAFE_OPERATIONS.includes(operation);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Bind a caller-owned key before the first effect and return a completed request without
|
|
15
|
+
* reapplying it. Incomplete rows fail closed: only a process that knows it never crossed the
|
|
16
|
+
* mutation boundary may discard its reservation and let the caller try again.
|
|
17
|
+
*/
|
|
18
|
+
export async function executeReplaySafeMutation(ctx, operation, parsedInput, work) {
|
|
19
|
+
const { idempotency_key: key, ...operationInput } = parsedInput;
|
|
20
|
+
if (!key)
|
|
21
|
+
return work(ctx, operationInput);
|
|
22
|
+
const requestHash = mutationRequestHash(operation, operationInput);
|
|
23
|
+
const identity = receiptIdentity(ctx.config.dbPath, ctx.actor, operation, key);
|
|
24
|
+
const existing = readReceipt(ctx.store, ctx.actor, operation, key);
|
|
25
|
+
if (existing) {
|
|
26
|
+
assertSameRequest(existing, requestHash);
|
|
27
|
+
if (existing.state === 'completed') {
|
|
28
|
+
return replayResult(ctx, operation, operationInput, existing);
|
|
29
|
+
}
|
|
30
|
+
if (activeReceipts.has(identity)) {
|
|
31
|
+
throw new AknoError('busy', `${operation} with this idempotency key is still running`, {
|
|
32
|
+
operation,
|
|
33
|
+
idempotency_key: key,
|
|
34
|
+
state: existing.state,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
throw interruptedError(existing);
|
|
38
|
+
}
|
|
39
|
+
const now = new Date().toISOString();
|
|
40
|
+
ctx.store.db
|
|
41
|
+
.prepare(`INSERT INTO mutation_receipts(
|
|
42
|
+
actor, operation, idempotency_key, request_hash, state, started_at
|
|
43
|
+
) VALUES(?, ?, ?, ?, 'reserved', ?)`)
|
|
44
|
+
.run(ctx.actor, operation, key, requestHash, now);
|
|
45
|
+
const receipt = {
|
|
46
|
+
actor: ctx.actor,
|
|
47
|
+
operation,
|
|
48
|
+
idempotencyKey: key,
|
|
49
|
+
requestHash,
|
|
50
|
+
started: false,
|
|
51
|
+
};
|
|
52
|
+
activeReceipts.add(identity);
|
|
53
|
+
try {
|
|
54
|
+
const result = await work({ ...ctx, mutationReceipt: receipt }, operationInput);
|
|
55
|
+
if (!receipt.started && isRetryablePrecondition(result)) {
|
|
56
|
+
deleteReceipt(ctx.store, receipt);
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
if (receipt.started)
|
|
60
|
+
assertJournalCommit(ctx.store, receipt, result);
|
|
61
|
+
const stored = compactResult(operation, result);
|
|
62
|
+
const updated = ctx.store.db
|
|
63
|
+
.prepare(`UPDATE mutation_receipts
|
|
64
|
+
SET state = 'completed', result = ?, completed_at = ?
|
|
65
|
+
WHERE actor = ? AND operation = ? AND idempotency_key = ? AND request_hash = ?
|
|
66
|
+
AND state IN ('reserved', 'running', 'committed')`)
|
|
67
|
+
.run(stored, new Date().toISOString(), ctx.actor, operation, key, requestHash);
|
|
68
|
+
if (updated.changes !== 1) {
|
|
69
|
+
throw new AknoError('internal', `could not complete the ${operation} mutation receipt`);
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
if (receipt.started) {
|
|
75
|
+
ctx.store.db
|
|
76
|
+
.prepare(`UPDATE mutation_receipts
|
|
77
|
+
SET state = 'interrupted', result = NULL, completed_at = NULL
|
|
78
|
+
WHERE actor = ? AND operation = ? AND idempotency_key = ? AND request_hash = ?
|
|
79
|
+
AND state IN ('running', 'committed')`)
|
|
80
|
+
.run(ctx.actor, operation, key, requestHash);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
deleteReceipt(ctx.store, receipt);
|
|
84
|
+
}
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
activeReceipts.delete(identity);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/** Mark the durable boundary immediately before the first filesystem effect. */
|
|
92
|
+
export function beginMutation(ctx) {
|
|
93
|
+
const receipt = ctx.mutationReceipt;
|
|
94
|
+
if (!receipt || receipt.started)
|
|
95
|
+
return;
|
|
96
|
+
const updated = ctx.store.db
|
|
97
|
+
.prepare(`UPDATE mutation_receipts SET state = 'running'
|
|
98
|
+
WHERE actor = ? AND operation = ? AND idempotency_key = ? AND request_hash = ?
|
|
99
|
+
AND state = 'reserved'`)
|
|
100
|
+
.run(receipt.actor, receipt.operation, receipt.idempotencyKey, receipt.requestHash);
|
|
101
|
+
if (updated.changes !== 1) {
|
|
102
|
+
throw new AknoError('internal', `could not start the ${receipt.operation} mutation receipt`);
|
|
103
|
+
}
|
|
104
|
+
receipt.started = true;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* A new writer proves the old process is gone. Reservations never reached the mutation boundary;
|
|
108
|
+
* every later state might have changed Markdown and therefore remains as an explicit interruption.
|
|
109
|
+
*/
|
|
110
|
+
export function recoverInterruptedMutationReceipts(ctx) {
|
|
111
|
+
if (!ctx.writable)
|
|
112
|
+
return;
|
|
113
|
+
ctx.store.transaction(() => {
|
|
114
|
+
const rows = ctx.store.db
|
|
115
|
+
.prepare("SELECT actor, operation, idempotency_key, state FROM mutation_receipts WHERE state != 'completed'")
|
|
116
|
+
.all();
|
|
117
|
+
const remove = ctx.store.db.prepare(`DELETE FROM mutation_receipts
|
|
118
|
+
WHERE actor = ? AND operation = ? AND idempotency_key = ? AND state = 'reserved'`);
|
|
119
|
+
const interrupt = ctx.store.db.prepare(`UPDATE mutation_receipts SET state = 'interrupted', result = NULL, completed_at = NULL
|
|
120
|
+
WHERE actor = ? AND operation = ? AND idempotency_key = ?
|
|
121
|
+
AND state IN ('running', 'committed')`);
|
|
122
|
+
for (const row of rows) {
|
|
123
|
+
if (activeReceipts.has(receiptIdentity(ctx.config.dbPath, row.actor, row.operation, row.idempotency_key))) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (row.state === 'reserved')
|
|
127
|
+
remove.run(row.actor, row.operation, row.idempotency_key);
|
|
128
|
+
else
|
|
129
|
+
interrupt.run(row.actor, row.operation, row.idempotency_key);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
function mutationRequestHash(operation, input) {
|
|
134
|
+
return sha256(stableJson({ operation, request: canonicalRequest(operation, input) }));
|
|
135
|
+
}
|
|
136
|
+
function canonicalRequest(operation, input) {
|
|
137
|
+
const request = withoutUndefined(input);
|
|
138
|
+
if (operation === 'write') {
|
|
139
|
+
if (typeof request.slug === 'string')
|
|
140
|
+
request.slug = normalizeSlug(request.slug);
|
|
141
|
+
if (typeof request.propose_slug === 'string')
|
|
142
|
+
request.propose_slug = normalizeSlug(request.propose_slug);
|
|
143
|
+
if (Array.isArray(request.documents)) {
|
|
144
|
+
request.documents = request.documents.map((document) => isRecord(document) && typeof document.path === 'string'
|
|
145
|
+
? { ...document, path: path.resolve(document.path) }
|
|
146
|
+
: document);
|
|
147
|
+
}
|
|
148
|
+
request.dry_run = request.dry_run ?? false;
|
|
149
|
+
}
|
|
150
|
+
else if (operation === 'move') {
|
|
151
|
+
if (typeof request.from === 'string')
|
|
152
|
+
request.from = normalizeSlug(request.from);
|
|
153
|
+
if (typeof request.to === 'string')
|
|
154
|
+
request.to = normalizeSlug(request.to);
|
|
155
|
+
}
|
|
156
|
+
else if (operation === 'forget') {
|
|
157
|
+
if (typeof request.slug === 'string')
|
|
158
|
+
request.slug = request.slug.replace(/\.(md|markdown)$/i, '');
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
if (typeof request.path === 'string')
|
|
162
|
+
request.path = normalizeSlug(request.path).replace(/\/\*+$/, '');
|
|
163
|
+
const role = typeof request.role === 'string' ? request.role : 'knowledge';
|
|
164
|
+
request.role = role;
|
|
165
|
+
request.remember = request.remember ?? (role === 'knowledge' ? 'integrate' : 'deny');
|
|
166
|
+
request.dry_run = request.dry_run ?? false;
|
|
167
|
+
}
|
|
168
|
+
return request;
|
|
169
|
+
}
|
|
170
|
+
function compactResult(operation, result) {
|
|
171
|
+
const safe = withoutUndefined({ ...result });
|
|
172
|
+
delete safe.removed;
|
|
173
|
+
delete safe.rule;
|
|
174
|
+
if (operation === 'folder' && result.rule !== undefined) {
|
|
175
|
+
if (result.outcome === 'noop') {
|
|
176
|
+
safe.rebuild_existing_rule = true;
|
|
177
|
+
safe.rule_hash = sha256(stableJson(result.rule));
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
safe.rebuild_rule = true;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
let encoded = stableJson(safe);
|
|
184
|
+
if (Buffer.byteLength(encoded) <= MAX_RESULT_BYTES)
|
|
185
|
+
return encoded;
|
|
186
|
+
const bounded = withoutUndefined({
|
|
187
|
+
status: result.status,
|
|
188
|
+
outcome: result.outcome,
|
|
189
|
+
change_id: result.change_id,
|
|
190
|
+
removed_from: result.removed_from,
|
|
191
|
+
trashed: result.trashed,
|
|
192
|
+
path: result.path,
|
|
193
|
+
glob: result.glob,
|
|
194
|
+
rules_file: result.rules_file,
|
|
195
|
+
result_truncated: true,
|
|
196
|
+
});
|
|
197
|
+
encoded = stableJson(bounded);
|
|
198
|
+
if (Buffer.byteLength(encoded) > MAX_RESULT_BYTES) {
|
|
199
|
+
throw new AknoError('internal', 'mutation result locator exceeded its storage bound');
|
|
200
|
+
}
|
|
201
|
+
return encoded;
|
|
202
|
+
}
|
|
203
|
+
function replayResult(ctx, operation, input, receipt) {
|
|
204
|
+
if (!receipt.result)
|
|
205
|
+
throw new AknoError('internal', 'completed mutation receipt has no result locator');
|
|
206
|
+
const result = JSON.parse(receipt.result);
|
|
207
|
+
if (result.rebuild_rule && operation === 'folder') {
|
|
208
|
+
result.rule = folderRuleFromRequest(input);
|
|
209
|
+
delete result.rebuild_rule;
|
|
210
|
+
}
|
|
211
|
+
if (result.rebuild_existing_rule && operation === 'folder' && typeof result.glob === 'string') {
|
|
212
|
+
const rule = currentFolderRule(ctx, result.glob);
|
|
213
|
+
if (rule && sha256(stableJson(rule)) === result.rule_hash)
|
|
214
|
+
result.rule = rule;
|
|
215
|
+
delete result.rebuild_existing_rule;
|
|
216
|
+
delete result.rule_hash;
|
|
217
|
+
}
|
|
218
|
+
if (operation === 'forget' && receipt.change_id && (input.fact || input.memory)) {
|
|
219
|
+
const removed = removedTextFromJournal(ctx.store, receipt.change_id);
|
|
220
|
+
if (removed !== null)
|
|
221
|
+
result.removed = removed;
|
|
222
|
+
}
|
|
223
|
+
delete result.result_truncated;
|
|
224
|
+
return { ...result, replayed: true };
|
|
225
|
+
}
|
|
226
|
+
function folderRuleFromRequest(input) {
|
|
227
|
+
const role = typeof input.role === 'string' ? input.role : 'knowledge';
|
|
228
|
+
return withoutUndefined({
|
|
229
|
+
description: input.description,
|
|
230
|
+
role,
|
|
231
|
+
remember: input.remember ?? (role === 'knowledge' ? 'integrate' : 'deny'),
|
|
232
|
+
about: input.about,
|
|
233
|
+
type: input.type,
|
|
234
|
+
ingest: input.ingest,
|
|
235
|
+
rank: input.rank,
|
|
236
|
+
route: input.route,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
function currentFolderRule(ctx, glob) {
|
|
240
|
+
const compiled = ctx.config.rules.find((rule) => rule.glob === glob);
|
|
241
|
+
if (!compiled)
|
|
242
|
+
return null;
|
|
243
|
+
const { glob: _glob, source: _source, specificity: _specificity, ...rule } = compiled;
|
|
244
|
+
return withoutUndefined(rule);
|
|
245
|
+
}
|
|
246
|
+
function removedTextFromJournal(store, changeId) {
|
|
247
|
+
const row = store.db
|
|
248
|
+
.prepare(`SELECT before, after FROM change_files
|
|
249
|
+
WHERE change_id = ? AND before IS NOT NULL AND after IS NOT NULL ORDER BY ord LIMIT 1`)
|
|
250
|
+
.get(changeId);
|
|
251
|
+
if (!row)
|
|
252
|
+
return null;
|
|
253
|
+
const before = row.before.split('\n');
|
|
254
|
+
const after = row.after.split('\n');
|
|
255
|
+
let prefix = 0;
|
|
256
|
+
while (prefix < before.length && prefix < after.length && before[prefix] === after[prefix])
|
|
257
|
+
prefix++;
|
|
258
|
+
let suffix = 0;
|
|
259
|
+
while (suffix < before.length - prefix &&
|
|
260
|
+
suffix < after.length - prefix &&
|
|
261
|
+
before[before.length - 1 - suffix] === after[after.length - 1 - suffix]) {
|
|
262
|
+
suffix++;
|
|
263
|
+
}
|
|
264
|
+
const removed = before.slice(prefix, before.length - suffix);
|
|
265
|
+
return removed.length > 0 ? removed.join('\n') : null;
|
|
266
|
+
}
|
|
267
|
+
function readReceipt(store, actor, operation, key) {
|
|
268
|
+
return store.db
|
|
269
|
+
.prepare(`SELECT * FROM mutation_receipts
|
|
270
|
+
WHERE actor = ? AND operation = ? AND idempotency_key = ?`)
|
|
271
|
+
.get(actor, operation, key);
|
|
272
|
+
}
|
|
273
|
+
function assertSameRequest(receipt, requestHash) {
|
|
274
|
+
if (receipt.request_hash === requestHash)
|
|
275
|
+
return;
|
|
276
|
+
throw new AknoError('conflict', 'this idempotency key is already bound to a different request', {
|
|
277
|
+
operation: receipt.operation,
|
|
278
|
+
idempotency_key: receipt.idempotency_key,
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
function assertJournalCommit(store, receipt, result) {
|
|
282
|
+
const row = readReceipt(store, receipt.actor, receipt.operation, receipt.idempotencyKey);
|
|
283
|
+
if (row?.state !== 'committed' ||
|
|
284
|
+
typeof result.change_id !== 'string' ||
|
|
285
|
+
row.change_id !== result.change_id) {
|
|
286
|
+
throw new AknoError('internal', `${receipt.operation} crossed its mutation boundary without an atomic journal commit`);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
function interruptedError(receipt) {
|
|
290
|
+
return new AknoError('interrupted', `${receipt.operation} with this idempotency key may already have changed the knowledge base`, {
|
|
291
|
+
operation: receipt.operation,
|
|
292
|
+
idempotency_key: receipt.idempotency_key,
|
|
293
|
+
state: receipt.state,
|
|
294
|
+
...(receipt.change_id ? { change_id: receipt.change_id } : {}),
|
|
295
|
+
recovery: receipt.change_id
|
|
296
|
+
? 'Inspect the recorded change before deciding whether to undo or continue with a new idempotency key.'
|
|
297
|
+
: 'Inspect the requested destination before continuing with a new idempotency key.',
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
function isRetryablePrecondition(result) {
|
|
301
|
+
return ['requires_folder', 'requires_approval', 'conflict'].includes(String(result.outcome));
|
|
302
|
+
}
|
|
303
|
+
function deleteReceipt(store, receipt) {
|
|
304
|
+
store.db
|
|
305
|
+
.prepare(`DELETE FROM mutation_receipts
|
|
306
|
+
WHERE actor = ? AND operation = ? AND idempotency_key = ? AND request_hash = ?`)
|
|
307
|
+
.run(receipt.actor, receipt.operation, receipt.idempotencyKey, receipt.requestHash);
|
|
308
|
+
}
|
|
309
|
+
function receiptIdentity(dbPath, actor, operation, key) {
|
|
310
|
+
return `${dbPath}\0${actor}\0${operation}\0${key}`;
|
|
311
|
+
}
|
|
312
|
+
function withoutUndefined(value) {
|
|
313
|
+
return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
|
|
314
|
+
}
|
|
315
|
+
function stableJson(value) {
|
|
316
|
+
return JSON.stringify(sortValue(value));
|
|
317
|
+
}
|
|
318
|
+
function sortValue(value) {
|
|
319
|
+
if (Array.isArray(value))
|
|
320
|
+
return value.map(sortValue);
|
|
321
|
+
if (!isRecord(value))
|
|
322
|
+
return value;
|
|
323
|
+
return Object.fromEntries(Object.keys(value)
|
|
324
|
+
.filter((key) => value[key] !== undefined)
|
|
325
|
+
.sort()
|
|
326
|
+
.map((key) => [key, sortValue(value[key])]));
|
|
327
|
+
}
|
|
328
|
+
function isRecord(value) {
|
|
329
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
330
|
+
}
|
|
331
|
+
//# sourceMappingURL=mutation-receipts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mutation-receipts.js","sourceRoot":"","sources":["../../src/write/mutation-receipts.ts"],"names":[],"mappings":"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"}
|
package/dist/write/retain.d.ts
CHANGED
|
@@ -7,8 +7,8 @@ import type { FolderCatalogEntry } from '../kb/folders.ts';
|
|
|
7
7
|
* consumed by keyed `retain` and unkeyed `remember`; keeping the interpretation here prevents
|
|
8
8
|
* the two public operations from gradually learning different meanings for the same source.
|
|
9
9
|
*/
|
|
10
|
-
export declare const RETAIN_PROMPT_VERSION = "retain-extraction-language-
|
|
11
|
-
export declare const RETAIN_VERIFIER_VERSION = "retain-verifier-language-
|
|
10
|
+
export declare const RETAIN_PROMPT_VERSION = "retain-extraction-language-v59";
|
|
11
|
+
export declare const RETAIN_VERIFIER_VERSION = "retain-verifier-language-v42";
|
|
12
12
|
/** All fields are required or nullable so constrained-decoding endpoints can keep strict mode. */
|
|
13
13
|
export declare const RETAIN_SCHEMA: z.ZodObject<{
|
|
14
14
|
candidates: z.ZodArray<z.ZodObject<{
|
|
@@ -149,7 +149,10 @@ export type RetainCandidate = ProvidedRetainCandidate & {
|
|
|
149
149
|
/** Compatibility fields consumed by the existing remember result and evidence archive. */
|
|
150
150
|
origin?: 'user' | 'assistant';
|
|
151
151
|
evidence?: string;
|
|
152
|
+
/** Verifier-derived boundary for automatic placement; never supplied by the extraction model. */
|
|
153
|
+
retention_scope?: RetentionScope;
|
|
152
154
|
};
|
|
155
|
+
type RetentionScope = 'global' | 'entity' | 'document' | 'event' | 'task' | 'unknown';
|
|
153
156
|
export interface RetainHeldCandidate {
|
|
154
157
|
hold_stage?: 'validation' | 'verification';
|
|
155
158
|
candidate_id: string;
|
|
@@ -203,4 +206,5 @@ export declare function cleanCandidateBatch(value: unknown, options: CandidateCl
|
|
|
203
206
|
held: RetainHeldCandidate[];
|
|
204
207
|
};
|
|
205
208
|
export declare function modelCallReceipt(model: ModelClient, outcome: ModelOutcome<unknown>): RetainModelCallReceipt;
|
|
209
|
+
export {};
|
|
206
210
|
//# sourceMappingURL=retain.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"retain.d.ts","sourceRoot":"","sources":["../../src/write/retain.ts"],"names":[],"mappings":"AAWA,OAAO,EAGL,KAAK,uBAAuB,EAC5B,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EAIrB,KAAK,cAAc,EACpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAkB,KAAK,WAAW,EAAE,KAAK,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAC1F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AA4B3D;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,mCAAmC,CAAC;AACtE,eAAO,MAAM,uBAAuB,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"retain.d.ts","sourceRoot":"","sources":["../../src/write/retain.ts"],"names":[],"mappings":"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"}
|
package/dist/write/retain.js
CHANGED
|
@@ -21,8 +21,8 @@ import { SEMANTIC_COMPARISON_CONTRACT, PROPOSITION_SCOPE_CONTRACT, aggregateSema
|
|
|
21
21
|
* consumed by keyed `retain` and unkeyed `remember`; keeping the interpretation here prevents
|
|
22
22
|
* the two public operations from gradually learning different meanings for the same source.
|
|
23
23
|
*/
|
|
24
|
-
export const RETAIN_PROMPT_VERSION = 'retain-extraction-language-
|
|
25
|
-
export const RETAIN_VERIFIER_VERSION = 'retain-verifier-language-
|
|
24
|
+
export const RETAIN_PROMPT_VERSION = 'retain-extraction-language-v59';
|
|
25
|
+
export const RETAIN_VERIFIER_VERSION = 'retain-verifier-language-v42';
|
|
26
26
|
const MAX_CANDIDATE_TEXT_UNITS = 400;
|
|
27
27
|
const RETRIEVAL_UNIT_CONTRACT = `A retained record is one independently retrievable semantic unit:
|
|
28
28
|
the selected proposition together with every source qualification governing its truth, knowledge state,
|
|
@@ -153,6 +153,9 @@ own sentence with an explicit subject, keeping exactly whether the person lacks
|
|
|
153
153
|
or personally performed a check. Choose subject and page after that qualified record. They describe its source-supported canonical identity,
|
|
154
154
|
not an action phrase constructed from its words. A proposed page is only a taxonomy suggestion, never proof
|
|
155
155
|
of ownership; use only the supplied admitted pages or creatable folders, and keep an unresolved home null.
|
|
156
|
+
For a durable document-scoped preference, choose the named document as subject, not merely the person
|
|
157
|
+
who expressed the preference. Never propose that person's general page, a bare year, or a domain index
|
|
158
|
+
as the document's home. If the document identity or home is unresolved, leave the page null.
|
|
156
159
|
When the outer narrator supplies a later corrective clarification of an inner report, close the inner
|
|
157
160
|
speaker's reported clause before the clarification and explicitly name the narrator as its source.
|
|
158
161
|
Keep both clauses in the same readable candidate with their shared verification limits. Do not move the
|
|
@@ -189,7 +192,12 @@ uses active, cancelled or superseded; question uses active or resolved. A questi
|
|
|
189
192
|
none: uncertainty about its answer does not make the question itself tentative or asserted.
|
|
190
193
|
|
|
191
194
|
Keep durable facts, accepted decisions, stated preferences, active plans, actual events, durable open
|
|
192
|
-
questions, and proven experience.
|
|
195
|
+
questions, and proven experience. A command to finish or clean up this one document or task is not
|
|
196
|
+
a standing preference, even when phrased in the first person. A question asked only to complete the
|
|
197
|
+
current task is not automatically a durable open question; an unresolved question worth returning to is.
|
|
198
|
+
Keep the original document, person, project, trip, or event scope in the readable record. Do not turn
|
|
199
|
+
an advertisement, quotation, or nearby project mention into a fact about that project. Keep a
|
|
200
|
+
considered, rejected, tentative, hypothetical, cancelled,
|
|
193
201
|
completed, or superseded item only when its readable sentence explicitly preserves that status.
|
|
194
202
|
When relevant to the supplied retention mission, discussed hypotheses, fictional examples, suspicions,
|
|
195
203
|
and unaccepted proposals are useful records too. Lack of established truth is not a reason to discard them.
|
|
@@ -319,6 +327,21 @@ actor, an asserted alternative, lost evidentiary limits or lost personal nonsele
|
|
|
319
327
|
For ordinary_tentative, tentative qualifies the selected uncertain proposition normally. Do not interpret
|
|
320
328
|
record-level metadata as syntactically modifying every verb regardless of the supplied label definition.
|
|
321
329
|
|
|
330
|
+
Independently classify retention admission from the complete source before approving placement.
|
|
331
|
+
For each candidate, retention.durability is durable only when the selected proposition remains useful
|
|
332
|
+
beyond this one source-processing task. A one-task command, a transient live reading, and a question
|
|
333
|
+
whose only purpose is finishing the current task are not durable. A genuine standing preference and
|
|
334
|
+
an unresolved question worth revisiting are durable, even if their wording is brief. Choose uncertain
|
|
335
|
+
when the source does not establish which. Classify source_scope from the selected source proposition,
|
|
336
|
+
not the candidate's proposed page or subject label. Classify candidate_scope from the readable text:
|
|
337
|
+
global for a standing preference across tasks, including a named person's cross-context preference;
|
|
338
|
+
entity for one named product/project/trip/booking or one person's specific profile fact,
|
|
339
|
+
document for one named document, event for one occurrence, task for a one-task instruction, and
|
|
340
|
+
unknown when the boundary is absent. A document-specific command restated as a global deletion
|
|
341
|
+
preference has source_scope=document and candidate_scope=global, even if its words are source-entailing
|
|
342
|
+
in isolation. Never widen a source's scope to make a destination convenient. Admission and factual
|
|
343
|
+
support are separate decisions: a faithful task-only record can still be held as not durable.
|
|
344
|
+
|
|
322
345
|
For every supplied candidate id, first audit its exact frame and use comparison.source_meaning and
|
|
323
346
|
comparison.candidate_meaning to identify the governing retained predicate and its actor separately from
|
|
324
347
|
subordinate or coupled propositions. Preserve every selected predicate and qualification; naming a governing
|
|
@@ -728,7 +751,12 @@ export async function runRetain(text, model, options = {}) {
|
|
|
728
751
|
modelUsage: { extraction: extractionReceipt, ...repairUsage, verification: verified.receipt },
|
|
729
752
|
};
|
|
730
753
|
}
|
|
731
|
-
const accepted = cleaned.candidates
|
|
754
|
+
const accepted = cleaned.candidates
|
|
755
|
+
.filter((candidate) => verified.accepted.has(candidate.candidate_id))
|
|
756
|
+
.map((candidate) => ({
|
|
757
|
+
...candidate,
|
|
758
|
+
retention_scope: verified.scopes.get(candidate.candidate_id),
|
|
759
|
+
}));
|
|
732
760
|
const heldByVerification = cleaned.candidates
|
|
733
761
|
.filter((candidate) => !verified.accepted.has(candidate.candidate_id))
|
|
734
762
|
.map((candidate) => ({
|
|
@@ -762,6 +790,7 @@ async function verifyCandidates(model, source, candidates, repairObligations, re
|
|
|
762
790
|
const outcomes = [];
|
|
763
791
|
const accepted = new Set();
|
|
764
792
|
const reasons = new Map();
|
|
793
|
+
const scopes = new Map();
|
|
765
794
|
// Two disjoint candidates fit the default derive-role ceiling without truncating a large batch.
|
|
766
795
|
// Relations still see the complete candidate context; candidates themselves are never evidence.
|
|
767
796
|
for (let start = 0; start < candidates.length; start += 2) {
|
|
@@ -772,6 +801,7 @@ async function verifyCandidates(model, source, candidates, repairObligations, re
|
|
|
772
801
|
return {
|
|
773
802
|
accepted: new Set(),
|
|
774
803
|
reasons: new Map(),
|
|
804
|
+
scopes: new Map(),
|
|
775
805
|
error: checked.error,
|
|
776
806
|
receipt: modelCallReceipt(model, aggregateSemanticOutcomes(outcomes)),
|
|
777
807
|
};
|
|
@@ -779,6 +809,8 @@ async function verifyCandidates(model, source, candidates, repairObligations, re
|
|
|
779
809
|
accepted.add(id);
|
|
780
810
|
for (const [id, reason] of checked.reasons)
|
|
781
811
|
reasons.set(id, reason);
|
|
812
|
+
for (const [id, scope] of checked.scopes)
|
|
813
|
+
scopes.set(id, scope);
|
|
782
814
|
}
|
|
783
815
|
// A source-supported relation still cannot persist when its target record was withheld.
|
|
784
816
|
// Iterate because a rejected target may invalidate a chain spanning several verification batches.
|
|
@@ -797,6 +829,7 @@ async function verifyCandidates(model, source, candidates, repairObligations, re
|
|
|
797
829
|
return {
|
|
798
830
|
accepted,
|
|
799
831
|
reasons,
|
|
832
|
+
scopes,
|
|
800
833
|
error: null,
|
|
801
834
|
receipt: modelCallReceipt(model, aggregateSemanticOutcomes(outcomes)),
|
|
802
835
|
};
|
|
@@ -832,6 +865,11 @@ async function verifyCandidateBatch(model, source, candidates, repairObligations
|
|
|
832
865
|
proposition_supported: semanticVerdictFields.proposition_supported,
|
|
833
866
|
action_arguments_preserved: semanticVerdictFields.action_arguments_preserved,
|
|
834
867
|
qualification_scope_preserved: semanticVerdictFields.qualification_scope_preserved,
|
|
868
|
+
retention: z.strictObject({
|
|
869
|
+
durability: z.enum(['durable', 'task_only', 'transient', 'uncertain']),
|
|
870
|
+
source_scope: z.enum(['global', 'entity', 'document', 'event', 'task', 'unknown']),
|
|
871
|
+
candidate_scope: z.enum(['global', 'entity', 'document', 'event', 'task', 'unknown']),
|
|
872
|
+
}),
|
|
835
873
|
reason_code: reason.nullable(),
|
|
836
874
|
});
|
|
837
875
|
});
|
|
@@ -889,6 +927,7 @@ async function verifyCandidateBatch(model, source, candidates, repairObligations
|
|
|
889
927
|
return {
|
|
890
928
|
accepted: new Set(),
|
|
891
929
|
reasons: new Map(),
|
|
930
|
+
scopes: new Map(),
|
|
892
931
|
outcome,
|
|
893
932
|
error: outcome.error ?? 'verification failed',
|
|
894
933
|
};
|
|
@@ -915,7 +954,13 @@ async function verifyCandidateBatch(model, source, candidates, repairObligations
|
|
|
915
954
|
verdict.qualification_scope_preserved) ||
|
|
916
955
|
verdict.reason_code === null))) {
|
|
917
956
|
model.reportInvalidResponse();
|
|
918
|
-
return {
|
|
957
|
+
return {
|
|
958
|
+
accepted: new Set(),
|
|
959
|
+
reasons: new Map(),
|
|
960
|
+
scopes: new Map(),
|
|
961
|
+
outcome,
|
|
962
|
+
error: 'verification returned invalid JSON',
|
|
963
|
+
};
|
|
919
964
|
}
|
|
920
965
|
const byId = new Map(parsed.data.verdicts.map((verdict) => [verdict.candidate_id, verdict]));
|
|
921
966
|
if (parsed.data.verdicts.length !== candidates.length ||
|
|
@@ -925,6 +970,7 @@ async function verifyCandidateBatch(model, source, candidates, repairObligations
|
|
|
925
970
|
return {
|
|
926
971
|
accepted: new Set(),
|
|
927
972
|
reasons: new Map(),
|
|
973
|
+
scopes: new Map(),
|
|
928
974
|
outcome,
|
|
929
975
|
error: 'verification omitted or duplicated candidate verdicts',
|
|
930
976
|
};
|
|
@@ -940,14 +986,35 @@ async function verifyCandidateBatch(model, source, candidates, repairObligations
|
|
|
940
986
|
// A source-side classification is compared with immutable metadata, independently of
|
|
941
987
|
// positive prose verdicts. Disagreement is a semantic hold, never permission to relabel.
|
|
942
988
|
verdict.source_selected_polarity ===
|
|
943
|
-
candidates.find((candidate) => candidate.candidate_id === verdict.candidate_id).polarity
|
|
989
|
+
candidates.find((candidate) => candidate.candidate_id === verdict.candidate_id).polarity &&
|
|
990
|
+
admissionReason(verdict.retention) === null)
|
|
944
991
|
.map((verdict) => verdict.candidate_id));
|
|
945
992
|
const reasons = new Map();
|
|
993
|
+
const scopes = new Map();
|
|
946
994
|
for (const verdict of parsed.data.verdicts) {
|
|
947
|
-
if (
|
|
948
|
-
|
|
995
|
+
if (accepted.has(verdict.candidate_id))
|
|
996
|
+
scopes.set(verdict.candidate_id, verdict.retention.source_scope);
|
|
997
|
+
if (!accepted.has(verdict.candidate_id)) {
|
|
998
|
+
const semanticFailure = !verdict.proposition_supported ||
|
|
999
|
+
!verdict.action_arguments_preserved ||
|
|
1000
|
+
!verdict.qualification_scope_preserved ||
|
|
1001
|
+
verdict.source_selected_polarity !==
|
|
1002
|
+
candidates.find((candidate) => candidate.candidate_id === verdict.candidate_id).polarity;
|
|
1003
|
+
reasons.set(verdict.candidate_id, semanticFailure
|
|
1004
|
+
? (verdict.reason_code ?? 'discourse_uncertain')
|
|
1005
|
+
: (verdict.reason_code ?? admissionReason(verdict.retention) ?? 'discourse_uncertain'));
|
|
1006
|
+
}
|
|
949
1007
|
}
|
|
950
|
-
return { accepted, reasons, outcome, error: null };
|
|
1008
|
+
return { accepted, reasons, scopes, outcome, error: null };
|
|
1009
|
+
}
|
|
1010
|
+
function admissionReason(retention) {
|
|
1011
|
+
if (retention.durability === 'task_only' || retention.durability === 'transient')
|
|
1012
|
+
return 'not_durable';
|
|
1013
|
+
if (retention.durability === 'uncertain' || retention.source_scope === 'unknown')
|
|
1014
|
+
return 'noncanonical_without_context';
|
|
1015
|
+
if (retention.source_scope !== retention.candidate_scope)
|
|
1016
|
+
return 'scope_mismatch';
|
|
1017
|
+
return retention.source_scope === 'task' ? 'scope_mismatch' : null;
|
|
951
1018
|
}
|
|
952
1019
|
/** Source spellings help classification; generated subjects cannot certify their own language. */
|
|
953
1020
|
function retentionLanguageReferences(source) {
|