@siduri-x/core 2.0.3 → 2.0.5
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/chat-contract.d.ts +4 -0
- package/dist/chat-contract.js +17 -2
- package/dist/context-retriever.d.ts +3 -0
- package/dist/context-retriever.js +23 -2
- package/dist/conversational-teach.test.d.ts +1 -0
- package/dist/conversational-teach.test.js +513 -0
- package/dist/index.d.ts +11 -3
- package/dist/memory-settler.d.ts +22 -1
- package/dist/memory-settler.js +70 -9
- package/dist/mouth-types.d.ts +7 -2
- package/dist/perception-pipeline.d.ts +1 -0
- package/dist/perception-pipeline.js +20 -2
- package/dist/prompt-compiler.d.ts +4 -0
- package/dist/prompt-compiler.js +8 -1
- package/dist/proposals.d.ts +2 -1
- package/dist/response-envelope.d.ts +4 -0
- package/dist/response-envelope.js +14 -3
- package/dist/runtime.d.ts +47 -1
- package/dist/runtime.js +209 -2
- package/dist/siduri-db.d.ts +14 -2
- package/dist/siduri-db.js +217 -127
- package/dist/siduri-db.test.js +19 -18
- package/dist/teaching.js +201 -12
- package/package.json +1 -1
package/dist/siduri-db.js
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SiduriDatabase = void 0;
|
|
4
|
+
exports.normalizeStatus = normalizeStatus;
|
|
4
5
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
5
6
|
const crypto = require('crypto');
|
|
6
7
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
7
8
|
const { DatabaseSync } = require('node:sqlite');
|
|
9
|
+
function normalizeStatus(status, defaultStatus = 'pending') {
|
|
10
|
+
if (!status)
|
|
11
|
+
return defaultStatus;
|
|
12
|
+
return status.toLowerCase().replace(/_/g, '-');
|
|
13
|
+
}
|
|
8
14
|
class SiduriDatabase {
|
|
9
15
|
db;
|
|
10
16
|
constructor(options = {}) {
|
|
@@ -20,6 +26,7 @@ class SiduriDatabase {
|
|
|
20
26
|
companion_id TEXT PRIMARY KEY,
|
|
21
27
|
name TEXT NOT NULL,
|
|
22
28
|
archetype TEXT,
|
|
29
|
+
role TEXT,
|
|
23
30
|
origin TEXT,
|
|
24
31
|
ethos TEXT,
|
|
25
32
|
version TEXT NOT NULL,
|
|
@@ -41,7 +48,7 @@ class SiduriDatabase {
|
|
|
41
48
|
companion_id TEXT NOT NULL,
|
|
42
49
|
priority INTEGER DEFAULT 50,
|
|
43
50
|
directive TEXT NOT NULL,
|
|
44
|
-
status TEXT DEFAULT '
|
|
51
|
+
status TEXT DEFAULT 'active',
|
|
45
52
|
category TEXT DEFAULT 'behavioral',
|
|
46
53
|
scope_actor TEXT,
|
|
47
54
|
supersedes_id TEXT,
|
|
@@ -123,7 +130,7 @@ class SiduriDatabase {
|
|
|
123
130
|
subject TEXT NOT NULL,
|
|
124
131
|
predicate TEXT NOT NULL,
|
|
125
132
|
value TEXT NOT NULL,
|
|
126
|
-
status TEXT DEFAULT '
|
|
133
|
+
status TEXT DEFAULT 'pending',
|
|
127
134
|
confidence REAL DEFAULT 1.0,
|
|
128
135
|
valid_from TEXT,
|
|
129
136
|
valid_until TEXT,
|
|
@@ -209,6 +216,12 @@ class SiduriDatabase {
|
|
|
209
216
|
catch {
|
|
210
217
|
// Column already exists
|
|
211
218
|
}
|
|
219
|
+
try {
|
|
220
|
+
this.db.exec("ALTER TABLE self_identity ADD COLUMN role TEXT");
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
// Column already exists
|
|
224
|
+
}
|
|
212
225
|
}
|
|
213
226
|
close() {
|
|
214
227
|
this.db.close();
|
|
@@ -225,6 +238,7 @@ class SiduriDatabase {
|
|
|
225
238
|
companionId: row.companion_id,
|
|
226
239
|
name: row.name,
|
|
227
240
|
archetype: row.archetype || undefined,
|
|
241
|
+
role: row.role || row.archetype || undefined,
|
|
228
242
|
origin: row.origin || undefined,
|
|
229
243
|
ethos: row.ethos || undefined,
|
|
230
244
|
version: row.version,
|
|
@@ -232,18 +246,21 @@ class SiduriDatabase {
|
|
|
232
246
|
};
|
|
233
247
|
}
|
|
234
248
|
setIdentity(identity) {
|
|
249
|
+
const role = identity.role || identity.archetype || null;
|
|
250
|
+
const archetype = identity.archetype || identity.role || null;
|
|
235
251
|
const stmt = this.db.prepare(`
|
|
236
|
-
INSERT INTO self_identity (companion_id, name, archetype, origin, ethos, version, updated_at)
|
|
237
|
-
VALUES (?, ?, ?, ?, ?, ?, datetime('now'))
|
|
252
|
+
INSERT INTO self_identity (companion_id, name, archetype, role, origin, ethos, version, updated_at)
|
|
253
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
238
254
|
ON CONFLICT(companion_id) DO UPDATE SET
|
|
239
255
|
name = excluded.name,
|
|
240
256
|
archetype = excluded.archetype,
|
|
257
|
+
role = excluded.role,
|
|
241
258
|
origin = excluded.origin,
|
|
242
259
|
ethos = excluded.ethos,
|
|
243
260
|
version = excluded.version,
|
|
244
261
|
updated_at = datetime('now')
|
|
245
262
|
`);
|
|
246
|
-
stmt.run(identity.companionId, identity.name,
|
|
263
|
+
stmt.run(identity.companionId, identity.name, archetype, role, identity.origin || null, identity.ethos || null, identity.version);
|
|
247
264
|
}
|
|
248
265
|
getPersonality(companionId) {
|
|
249
266
|
const stmt = this.db.prepare('SELECT * FROM self_personality WHERE companion_id = ?');
|
|
@@ -272,30 +289,49 @@ class SiduriDatabase {
|
|
|
272
289
|
`);
|
|
273
290
|
stmt.run(companionId, traits.warmth, traits.formality, traits.sarcasm, traits.verbosity, traits.curiosity);
|
|
274
291
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
SELECT * FROM self_directives
|
|
278
|
-
WHERE companion_id = ? AND status = 'ACTIVE'
|
|
279
|
-
ORDER BY priority DESC, created_at ASC
|
|
280
|
-
`);
|
|
281
|
-
return stmt.all(companionId).map((row) => ({
|
|
292
|
+
rowToSelfDirective(row) {
|
|
293
|
+
return {
|
|
282
294
|
id: row.id,
|
|
283
295
|
companionId: row.companion_id,
|
|
284
296
|
priority: row.priority,
|
|
285
297
|
directive: row.directive,
|
|
286
|
-
status: row.status,
|
|
298
|
+
status: normalizeStatus(row.status, 'active'),
|
|
287
299
|
category: row.category,
|
|
288
300
|
scopeActor: row.scope_actor || undefined,
|
|
289
301
|
supersedesId: row.supersedes_id || undefined,
|
|
290
|
-
createdAt: row.created_at
|
|
291
|
-
}
|
|
302
|
+
createdAt: row.created_at,
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
getActiveDirectives(companionId) {
|
|
306
|
+
const stmt = this.db.prepare(`
|
|
307
|
+
SELECT * FROM self_directives
|
|
308
|
+
WHERE companion_id = ? AND LOWER(status) = 'active'
|
|
309
|
+
ORDER BY priority DESC, created_at ASC
|
|
310
|
+
`);
|
|
311
|
+
return stmt.all(companionId).map((row) => this.rowToSelfDirective(row));
|
|
312
|
+
}
|
|
313
|
+
getAllDirectives(companionId) {
|
|
314
|
+
const stmt = this.db.prepare(`
|
|
315
|
+
SELECT * FROM self_directives
|
|
316
|
+
WHERE companion_id = ?
|
|
317
|
+
ORDER BY priority DESC, created_at ASC
|
|
318
|
+
`);
|
|
319
|
+
return stmt.all(companionId).map((row) => this.rowToSelfDirective(row));
|
|
292
320
|
}
|
|
293
321
|
commitDirective(directive) {
|
|
294
322
|
const stmt = this.db.prepare(`
|
|
295
323
|
INSERT INTO self_directives (id, companion_id, priority, directive, status, category, scope_actor, supersedes_id, created_at)
|
|
296
324
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
325
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
326
|
+
companion_id = excluded.companion_id,
|
|
327
|
+
priority = excluded.priority,
|
|
328
|
+
directive = excluded.directive,
|
|
329
|
+
status = excluded.status,
|
|
330
|
+
category = excluded.category,
|
|
331
|
+
scope_actor = excluded.scope_actor,
|
|
332
|
+
supersedes_id = excluded.supersedes_id
|
|
297
333
|
`);
|
|
298
|
-
stmt.run(directive.id, directive.companionId, directive.priority !== undefined ? directive.priority : 50, directive.directive, directive.status, directive.category || 'behavioral', directive.scopeActor || null, directive.supersedesId || null, directive.createdAt || new Date().toISOString());
|
|
334
|
+
stmt.run(directive.id, directive.companionId, directive.priority !== undefined ? directive.priority : 50, directive.directive, normalizeStatus(directive.status, 'active'), directive.category || 'behavioral', directive.scopeActor || null, directive.supersedesId || null, directive.createdAt || new Date().toISOString());
|
|
299
335
|
}
|
|
300
336
|
getDirective(id, companionId) {
|
|
301
337
|
const stmt = companionId
|
|
@@ -304,17 +340,7 @@ class SiduriDatabase {
|
|
|
304
340
|
const row = (companionId ? stmt.get(id, companionId) : stmt.get(id));
|
|
305
341
|
if (!row)
|
|
306
342
|
return undefined;
|
|
307
|
-
return
|
|
308
|
-
id: row.id,
|
|
309
|
-
companionId: row.companion_id,
|
|
310
|
-
priority: row.priority,
|
|
311
|
-
directive: row.directive,
|
|
312
|
-
status: row.status,
|
|
313
|
-
category: row.category,
|
|
314
|
-
scopeActor: row.scope_actor || undefined,
|
|
315
|
-
supersedesId: row.supersedes_id || undefined,
|
|
316
|
-
createdAt: row.created_at,
|
|
317
|
-
};
|
|
343
|
+
return this.rowToSelfDirective(row);
|
|
318
344
|
}
|
|
319
345
|
approveDirective(id, companionId) {
|
|
320
346
|
const findStmt = companionId
|
|
@@ -324,28 +350,31 @@ class SiduriDatabase {
|
|
|
324
350
|
if (!row) {
|
|
325
351
|
return;
|
|
326
352
|
}
|
|
327
|
-
if (row.status !== '
|
|
328
|
-
|
|
353
|
+
if (normalizeStatus(row.status) !== 'pending') {
|
|
354
|
+
if (normalizeStatus(row.status) === 'active') {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
throw new Error(`Cannot approve directive '${id}': invalid transition from status '${row.status}' to 'active' (only pending directives can be approved)`);
|
|
329
358
|
}
|
|
330
|
-
// If this directive supersedes an earlier directive, transition that prior directive to
|
|
359
|
+
// If this directive supersedes an earlier directive, transition that prior directive to superseded
|
|
331
360
|
if (row.supersedes_id) {
|
|
332
361
|
const supersededId = row.supersedes_id;
|
|
333
362
|
const effectiveCompanionId = companionId || row.companion_id;
|
|
334
363
|
if (effectiveCompanionId) {
|
|
335
|
-
const supersedeStmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
364
|
+
const supersedeStmt = this.db.prepare("UPDATE self_directives SET status = 'superseded' WHERE id = ? AND companion_id = ?");
|
|
336
365
|
supersedeStmt.run(supersededId, effectiveCompanionId);
|
|
337
366
|
}
|
|
338
367
|
else {
|
|
339
|
-
const supersedeStmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
368
|
+
const supersedeStmt = this.db.prepare("UPDATE self_directives SET status = 'superseded' WHERE id = ?");
|
|
340
369
|
supersedeStmt.run(supersededId);
|
|
341
370
|
}
|
|
342
371
|
}
|
|
343
372
|
if (companionId) {
|
|
344
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
373
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'active' WHERE id = ? AND companion_id = ? AND LOWER(status) = 'pending'");
|
|
345
374
|
stmt.run(id, companionId);
|
|
346
375
|
}
|
|
347
376
|
else {
|
|
348
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
377
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'active' WHERE id = ? AND LOWER(status) = 'pending'");
|
|
349
378
|
stmt.run(id);
|
|
350
379
|
}
|
|
351
380
|
}
|
|
@@ -357,51 +386,53 @@ class SiduriDatabase {
|
|
|
357
386
|
if (!row) {
|
|
358
387
|
return;
|
|
359
388
|
}
|
|
360
|
-
if (row.status !== '
|
|
361
|
-
throw new Error(`Cannot reject directive '${id}': invalid transition from status '${row.status}' to '
|
|
389
|
+
if (normalizeStatus(row.status) !== 'pending') {
|
|
390
|
+
throw new Error(`Cannot reject directive '${id}': invalid transition from status '${row.status}' to 'rejected' (only pending directives can be rejected)`);
|
|
362
391
|
}
|
|
363
392
|
if (companionId) {
|
|
364
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
393
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'rejected' WHERE id = ? AND companion_id = ? AND LOWER(status) = 'pending'");
|
|
365
394
|
stmt.run(id, companionId);
|
|
366
395
|
}
|
|
367
396
|
else {
|
|
368
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
397
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'rejected' WHERE id = ? AND LOWER(status) = 'pending'");
|
|
369
398
|
stmt.run(id);
|
|
370
399
|
}
|
|
371
400
|
}
|
|
372
401
|
revokeDirective(id, companionId) {
|
|
373
402
|
if (companionId) {
|
|
374
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
403
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'revoked' WHERE id = ? AND companion_id = ?");
|
|
375
404
|
stmt.run(id, companionId);
|
|
376
405
|
}
|
|
377
406
|
else {
|
|
378
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
407
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'revoked' WHERE id = ?");
|
|
379
408
|
stmt.run(id);
|
|
380
409
|
}
|
|
381
410
|
}
|
|
382
411
|
expireDirective(id, companionId) {
|
|
383
412
|
if (companionId) {
|
|
384
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
413
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'expired' WHERE id = ? AND companion_id = ?");
|
|
385
414
|
stmt.run(id, companionId);
|
|
386
415
|
}
|
|
387
416
|
else {
|
|
388
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
417
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'expired' WHERE id = ?");
|
|
389
418
|
stmt.run(id);
|
|
390
419
|
}
|
|
391
420
|
}
|
|
392
421
|
disableDirective(id, companionId) {
|
|
393
422
|
if (companionId) {
|
|
394
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
423
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'disabled' WHERE id = ? AND companion_id = ?");
|
|
395
424
|
stmt.run(id, companionId);
|
|
396
425
|
}
|
|
397
426
|
else {
|
|
398
|
-
const stmt = this.db.prepare("UPDATE self_directives SET status = '
|
|
427
|
+
const stmt = this.db.prepare("UPDATE self_directives SET status = 'disabled' WHERE id = ?");
|
|
399
428
|
stmt.run(id);
|
|
400
429
|
}
|
|
401
430
|
}
|
|
402
431
|
getRelationship(companionId, entityId) {
|
|
403
|
-
const
|
|
404
|
-
const
|
|
432
|
+
const stripped = entityId.startsWith('actor:') ? entityId.slice(6) : entityId;
|
|
433
|
+
const prefixed = entityId.startsWith('actor:') ? entityId : `actor:${entityId}`;
|
|
434
|
+
const stmt = this.db.prepare('SELECT * FROM self_relationships WHERE companion_id = ? AND (entity_id = ? OR entity_id = ? OR entity_id = ?)');
|
|
435
|
+
const row = stmt.get(companionId, entityId, stripped, prefixed);
|
|
405
436
|
if (!row)
|
|
406
437
|
return undefined;
|
|
407
438
|
return {
|
|
@@ -603,20 +634,37 @@ class SiduriDatabase {
|
|
|
603
634
|
payload: JSON.parse(row.payload)
|
|
604
635
|
};
|
|
605
636
|
}
|
|
637
|
+
rowToMemoryClaim(row) {
|
|
638
|
+
return {
|
|
639
|
+
id: row.id,
|
|
640
|
+
companionId: row.companion_id,
|
|
641
|
+
subject: row.subject,
|
|
642
|
+
predicate: row.predicate,
|
|
643
|
+
value: row.value,
|
|
644
|
+
status: normalizeStatus(row.status, 'pending'),
|
|
645
|
+
confidence: row.confidence,
|
|
646
|
+
validFrom: row.valid_from || undefined,
|
|
647
|
+
validUntil: row.valid_until || undefined,
|
|
648
|
+
evidence: row.evidence ? (typeof row.evidence === 'string' ? JSON.parse(row.evidence) : row.evidence) : undefined,
|
|
649
|
+
assertedAt: row.asserted_at,
|
|
650
|
+
supersedes: row.supersedes || undefined,
|
|
651
|
+
sourceEventId: row.source_event_id || undefined,
|
|
652
|
+
};
|
|
653
|
+
}
|
|
606
654
|
proposeClaim(claim) {
|
|
607
655
|
const id = claim.id || crypto.randomUUID();
|
|
608
|
-
const status = '
|
|
656
|
+
const status = normalizeStatus(claim.status, 'pending');
|
|
609
657
|
const confidence = claim.confidence ?? 1.0;
|
|
610
658
|
const assertedAt = claim.assertedAt || new Date().toISOString();
|
|
611
659
|
const stmt = this.db.prepare(`
|
|
612
660
|
INSERT INTO memory_claims (id, companion_id, subject, predicate, value, status, confidence, valid_from, valid_until, evidence, asserted_at, supersedes, source_event_id)
|
|
613
661
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, coalesce(?, datetime('now')), ?, ?)
|
|
614
662
|
`);
|
|
615
|
-
stmt.run(id, claim.companionId, claim.subject, claim.predicate, claim.value, status, confidence, claim.validFrom || null, claim.validUntil || null, claim.evidence ? JSON.stringify(claim.evidence) : null, assertedAt || null, claim.supersedes || null, claim.sourceEventId || null);
|
|
663
|
+
stmt.run(id, claim.companionId || 'default', claim.subject, claim.predicate, claim.value, status, confidence, claim.validFrom || null, claim.validUntil || null, claim.evidence ? JSON.stringify(claim.evidence) : null, assertedAt || null, claim.supersedes || null, claim.sourceEventId || null);
|
|
616
664
|
return {
|
|
617
665
|
...claim,
|
|
618
666
|
id,
|
|
619
|
-
status,
|
|
667
|
+
status: status,
|
|
620
668
|
confidence,
|
|
621
669
|
assertedAt,
|
|
622
670
|
supersedes: claim.supersedes,
|
|
@@ -631,67 +679,158 @@ class SiduriDatabase {
|
|
|
631
679
|
if (!row) {
|
|
632
680
|
return;
|
|
633
681
|
}
|
|
634
|
-
if (row.status !== '
|
|
635
|
-
|
|
682
|
+
if (normalizeStatus(row.status) !== 'pending') {
|
|
683
|
+
if (normalizeStatus(row.status) === 'approved') {
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
686
|
+
throw new Error(`Cannot approve claim '${id}': invalid transition from status '${row.status}' to 'approved' (only pending claims can be approved)`);
|
|
636
687
|
}
|
|
637
|
-
// If this claim supersedes an earlier claim, transition that prior claim to
|
|
688
|
+
// If this claim supersedes an earlier claim, transition that prior claim to superseded
|
|
638
689
|
if (row.supersedes) {
|
|
639
690
|
const supersededId = row.supersedes;
|
|
640
691
|
if (companionId) {
|
|
641
|
-
const supersedeStmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
692
|
+
const supersedeStmt = this.db.prepare("UPDATE memory_claims SET status = 'superseded' WHERE id = ? AND companion_id = ?");
|
|
642
693
|
supersedeStmt.run(supersededId, companionId);
|
|
643
694
|
}
|
|
644
695
|
else {
|
|
645
|
-
const supersedeStmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
696
|
+
const supersedeStmt = this.db.prepare("UPDATE memory_claims SET status = 'superseded' WHERE id = ?");
|
|
646
697
|
supersedeStmt.run(supersededId);
|
|
647
698
|
}
|
|
648
699
|
}
|
|
649
700
|
if (companionId) {
|
|
650
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
701
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'approved' WHERE id = ? AND companion_id = ? AND LOWER(status) = 'pending'");
|
|
651
702
|
stmt.run(id, companionId);
|
|
652
703
|
}
|
|
653
704
|
else {
|
|
654
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
705
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'approved' WHERE id = ? AND LOWER(status) = 'pending'");
|
|
655
706
|
stmt.run(id);
|
|
656
707
|
}
|
|
708
|
+
// Canonically promote approved claim to Self domain state (identity, role, relationships)
|
|
709
|
+
const approvedClaim = this.getClaim(id);
|
|
710
|
+
if (approvedClaim) {
|
|
711
|
+
this.promoteClaimToSelf(approvedClaim);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Canonically promotes a Claim into Self domain tables.
|
|
716
|
+
*/
|
|
717
|
+
promoteClaimToSelf(claim) {
|
|
718
|
+
const companionId = claim.companionId || 'default';
|
|
719
|
+
const subject = (claim.subject || '').toLowerCase();
|
|
720
|
+
const predicate = (claim.predicate || '').toLowerCase();
|
|
721
|
+
const value = claim.value || '';
|
|
722
|
+
if (!value)
|
|
723
|
+
return;
|
|
724
|
+
// 1. Identity mutations: companion identity/role/origin/name/ethos
|
|
725
|
+
if (subject.startsWith('companion:') ||
|
|
726
|
+
subject === 'companion' ||
|
|
727
|
+
subject === 'siduri' ||
|
|
728
|
+
subject === 'self') {
|
|
729
|
+
const existing = this.getIdentity(companionId) || {
|
|
730
|
+
companionId,
|
|
731
|
+
name: 'Siduri',
|
|
732
|
+
version: '1.0.0',
|
|
733
|
+
updatedAt: new Date().toISOString(),
|
|
734
|
+
};
|
|
735
|
+
if (predicate === 'role' || predicate === 'archetype') {
|
|
736
|
+
existing.archetype = value;
|
|
737
|
+
existing.role = value;
|
|
738
|
+
this.setIdentity(existing);
|
|
739
|
+
this.commitDirective({
|
|
740
|
+
id: `dir-role-${claim.id || Date.now()}`,
|
|
741
|
+
companionId,
|
|
742
|
+
priority: 70,
|
|
743
|
+
directive: `Acknowledge role as ${value}`,
|
|
744
|
+
status: 'active',
|
|
745
|
+
category: 'relational',
|
|
746
|
+
createdAt: new Date().toISOString(),
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
else if (predicate === 'origin' || predicate === 'created_by') {
|
|
750
|
+
existing.origin = value;
|
|
751
|
+
this.setIdentity(existing);
|
|
752
|
+
}
|
|
753
|
+
else if (predicate === 'name') {
|
|
754
|
+
existing.name = value;
|
|
755
|
+
this.setIdentity(existing);
|
|
756
|
+
}
|
|
757
|
+
else if (predicate === 'ethos') {
|
|
758
|
+
existing.ethos = value;
|
|
759
|
+
this.setIdentity(existing);
|
|
760
|
+
}
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
// 2. Relationship mutations: creator or user stated relationship
|
|
764
|
+
if (claim.claimType === 'relationship' ||
|
|
765
|
+
predicate === 'stated_relationship' ||
|
|
766
|
+
predicate === 'relationship' ||
|
|
767
|
+
predicate === 'relationship_to_siduri') {
|
|
768
|
+
const rawSubject = (claim.subject || 'actor:user').replace(/^actor:actor:/, 'actor:');
|
|
769
|
+
const isCreator = value.toLowerCase() === 'creator';
|
|
770
|
+
this.upsertRelationship({
|
|
771
|
+
companionId,
|
|
772
|
+
entityId: rawSubject,
|
|
773
|
+
entityType: 'human',
|
|
774
|
+
role: value,
|
|
775
|
+
stance: isCreator ? 'familiar_loyal' : 'neutral',
|
|
776
|
+
trustScore: isCreator ? 1.0 : 0.8,
|
|
777
|
+
familiarity: isCreator ? 0.9 : 0.5,
|
|
778
|
+
interactionConventions: isCreator
|
|
779
|
+
? ['Direct communication', 'Highest administrative trust']
|
|
780
|
+
: [],
|
|
781
|
+
});
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
// 3. Behavioral rule claim
|
|
785
|
+
if (predicate === 'behavioral_rule' || predicate === 'rule') {
|
|
786
|
+
this.commitDirective({
|
|
787
|
+
id: `dir-rule-${claim.id || Date.now()}`,
|
|
788
|
+
companionId,
|
|
789
|
+
priority: 60,
|
|
790
|
+
directive: value,
|
|
791
|
+
status: 'active',
|
|
792
|
+
category: 'behavioral',
|
|
793
|
+
createdAt: new Date().toISOString(),
|
|
794
|
+
});
|
|
795
|
+
}
|
|
657
796
|
}
|
|
658
797
|
rejectClaim(id, companionId) {
|
|
659
798
|
if (companionId) {
|
|
660
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
799
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'rejected' WHERE id = ? AND companion_id = ?");
|
|
661
800
|
stmt.run(id, companionId);
|
|
662
801
|
}
|
|
663
802
|
else {
|
|
664
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
803
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'rejected' WHERE id = ?");
|
|
665
804
|
stmt.run(id);
|
|
666
805
|
}
|
|
667
806
|
}
|
|
668
807
|
revokeClaim(id, companionId) {
|
|
669
808
|
if (companionId) {
|
|
670
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
809
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'revoked' WHERE id = ? AND companion_id = ?");
|
|
671
810
|
stmt.run(id, companionId);
|
|
672
811
|
}
|
|
673
812
|
else {
|
|
674
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
813
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'revoked' WHERE id = ?");
|
|
675
814
|
stmt.run(id);
|
|
676
815
|
}
|
|
677
816
|
}
|
|
678
817
|
expireClaim(id, companionId) {
|
|
679
818
|
if (companionId) {
|
|
680
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
819
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'expired' WHERE id = ? AND companion_id = ?");
|
|
681
820
|
stmt.run(id, companionId);
|
|
682
821
|
}
|
|
683
822
|
else {
|
|
684
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
823
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'expired' WHERE id = ?");
|
|
685
824
|
stmt.run(id);
|
|
686
825
|
}
|
|
687
826
|
}
|
|
688
827
|
markClaimSessionOnly(id, companionId) {
|
|
689
828
|
if (companionId) {
|
|
690
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
829
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'session-only' WHERE id = ? AND companion_id = ?");
|
|
691
830
|
stmt.run(id, companionId);
|
|
692
831
|
}
|
|
693
832
|
else {
|
|
694
|
-
const stmt = this.db.prepare("UPDATE memory_claims SET status = '
|
|
833
|
+
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'session-only' WHERE id = ?");
|
|
695
834
|
stmt.run(id);
|
|
696
835
|
}
|
|
697
836
|
}
|
|
@@ -699,82 +838,33 @@ class SiduriDatabase {
|
|
|
699
838
|
const stmt = this.db.prepare(`
|
|
700
839
|
SELECT c.* FROM memory_claims c
|
|
701
840
|
JOIN memory_search s ON c.rowid = s.rowid
|
|
702
|
-
WHERE c.companion_id = ? AND c.status = '
|
|
841
|
+
WHERE c.companion_id = ? AND LOWER(c.status) = 'approved' AND memory_search MATCH ?
|
|
703
842
|
ORDER BY rank
|
|
704
843
|
LIMIT ?
|
|
705
844
|
`);
|
|
706
|
-
return stmt.all(companionId, query, limit).map((row) => (
|
|
707
|
-
id: row.id,
|
|
708
|
-
companionId: row.companion_id,
|
|
709
|
-
subject: row.subject,
|
|
710
|
-
predicate: row.predicate,
|
|
711
|
-
value: row.value,
|
|
712
|
-
status: row.status,
|
|
713
|
-
confidence: row.confidence,
|
|
714
|
-
validFrom: row.valid_from || undefined,
|
|
715
|
-
validUntil: row.valid_until || undefined,
|
|
716
|
-
evidence: row.evidence ? JSON.parse(row.evidence) : undefined,
|
|
717
|
-
assertedAt: row.asserted_at,
|
|
718
|
-
supersedes: row.supersedes || undefined,
|
|
719
|
-
sourceEventId: row.source_event_id || undefined,
|
|
720
|
-
}));
|
|
845
|
+
return stmt.all(companionId, query, limit).map((row) => this.rowToMemoryClaim(row));
|
|
721
846
|
}
|
|
722
847
|
getPendingClaims(companionId, limit = 50) {
|
|
723
|
-
const stmt = this.db.prepare("SELECT * FROM memory_claims WHERE companion_id = ? AND status = '
|
|
724
|
-
return stmt.all(companionId, limit).map((row) => (
|
|
725
|
-
id: row.id,
|
|
726
|
-
companionId: row.companion_id,
|
|
727
|
-
subject: row.subject,
|
|
728
|
-
predicate: row.predicate,
|
|
729
|
-
value: row.value,
|
|
730
|
-
status: row.status,
|
|
731
|
-
confidence: row.confidence,
|
|
732
|
-
validFrom: row.valid_from || undefined,
|
|
733
|
-
validUntil: row.valid_until || undefined,
|
|
734
|
-
evidence: row.evidence ? JSON.parse(row.evidence) : undefined,
|
|
735
|
-
assertedAt: row.asserted_at,
|
|
736
|
-
supersedes: row.supersedes || undefined,
|
|
737
|
-
sourceEventId: row.source_event_id || undefined,
|
|
738
|
-
}));
|
|
848
|
+
const stmt = this.db.prepare("SELECT * FROM memory_claims WHERE companion_id = ? AND LOWER(status) = 'pending' ORDER BY asserted_at DESC LIMIT ?");
|
|
849
|
+
return stmt.all(companionId, limit).map((row) => this.rowToMemoryClaim(row));
|
|
739
850
|
}
|
|
740
851
|
getApprovedClaims(companionId, limit = 50) {
|
|
741
|
-
const stmt = this.db.prepare("SELECT * FROM memory_claims WHERE companion_id = ? AND status = '
|
|
742
|
-
return stmt.all(companionId, limit).map((row) => (
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
validFrom: row.valid_from || undefined,
|
|
751
|
-
validUntil: row.valid_until || undefined,
|
|
752
|
-
evidence: row.evidence ? JSON.parse(row.evidence) : undefined,
|
|
753
|
-
assertedAt: row.asserted_at,
|
|
754
|
-
supersedes: row.supersedes || undefined,
|
|
755
|
-
sourceEventId: row.source_event_id || undefined,
|
|
756
|
-
}));
|
|
852
|
+
const stmt = this.db.prepare("SELECT * FROM memory_claims WHERE companion_id = ? AND LOWER(status) = 'approved' ORDER BY asserted_at DESC LIMIT ?");
|
|
853
|
+
return stmt.all(companionId, limit).map((row) => this.rowToMemoryClaim(row));
|
|
854
|
+
}
|
|
855
|
+
getAllClaims(companionId, limit = 100) {
|
|
856
|
+
const stmt = companionId
|
|
857
|
+
? this.db.prepare("SELECT * FROM memory_claims WHERE companion_id = ? ORDER BY asserted_at DESC LIMIT ?")
|
|
858
|
+
: this.db.prepare("SELECT * FROM memory_claims ORDER BY asserted_at DESC LIMIT ?");
|
|
859
|
+
const rows = companionId ? stmt.all(companionId, limit) : stmt.all(limit);
|
|
860
|
+
return rows.map((row) => this.rowToMemoryClaim(row));
|
|
757
861
|
}
|
|
758
862
|
getClaim(id) {
|
|
759
863
|
const stmt = this.db.prepare("SELECT * FROM memory_claims WHERE id = ?");
|
|
760
864
|
const row = stmt.get(id);
|
|
761
865
|
if (!row)
|
|
762
866
|
return undefined;
|
|
763
|
-
return
|
|
764
|
-
id: row.id,
|
|
765
|
-
companionId: row.companion_id,
|
|
766
|
-
subject: row.subject,
|
|
767
|
-
predicate: row.predicate,
|
|
768
|
-
value: row.value,
|
|
769
|
-
status: row.status,
|
|
770
|
-
confidence: row.confidence,
|
|
771
|
-
validFrom: row.valid_from || undefined,
|
|
772
|
-
validUntil: row.valid_until || undefined,
|
|
773
|
-
evidence: row.evidence ? JSON.parse(row.evidence) : undefined,
|
|
774
|
-
assertedAt: row.asserted_at,
|
|
775
|
-
supersedes: row.supersedes || undefined,
|
|
776
|
-
sourceEventId: row.source_event_id || undefined,
|
|
777
|
-
};
|
|
867
|
+
return this.rowToMemoryClaim(row);
|
|
778
868
|
}
|
|
779
869
|
resetMemory(companionId) {
|
|
780
870
|
const deleteClaims = this.db.prepare("DELETE FROM memory_claims WHERE companion_id = ?");
|