@siduri-x/core 2.0.4 → 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/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 +7 -1
- package/dist/memory-settler.d.ts +22 -1
- package/dist/memory-settler.js +69 -8
- package/dist/perception-pipeline.js +13 -2
- package/dist/prompt-compiler.d.ts +3 -0
- package/dist/prompt-compiler.js +4 -1
- package/dist/response-envelope.d.ts +1 -0
- package/dist/response-envelope.js +2 -1
- package/dist/runtime.d.ts +46 -0
- package/dist/runtime.js +207 -1
- package/dist/siduri-db.d.ts +5 -0
- package/dist/siduri-db.js +121 -6
- package/dist/siduri-db.test.js +2 -1
- package/dist/teaching.js +201 -12
- package/package.json +1 -1
package/dist/siduri-db.js
CHANGED
|
@@ -26,6 +26,7 @@ class SiduriDatabase {
|
|
|
26
26
|
companion_id TEXT PRIMARY KEY,
|
|
27
27
|
name TEXT NOT NULL,
|
|
28
28
|
archetype TEXT,
|
|
29
|
+
role TEXT,
|
|
29
30
|
origin TEXT,
|
|
30
31
|
ethos TEXT,
|
|
31
32
|
version TEXT NOT NULL,
|
|
@@ -215,6 +216,12 @@ class SiduriDatabase {
|
|
|
215
216
|
catch {
|
|
216
217
|
// Column already exists
|
|
217
218
|
}
|
|
219
|
+
try {
|
|
220
|
+
this.db.exec("ALTER TABLE self_identity ADD COLUMN role TEXT");
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
// Column already exists
|
|
224
|
+
}
|
|
218
225
|
}
|
|
219
226
|
close() {
|
|
220
227
|
this.db.close();
|
|
@@ -231,6 +238,7 @@ class SiduriDatabase {
|
|
|
231
238
|
companionId: row.companion_id,
|
|
232
239
|
name: row.name,
|
|
233
240
|
archetype: row.archetype || undefined,
|
|
241
|
+
role: row.role || row.archetype || undefined,
|
|
234
242
|
origin: row.origin || undefined,
|
|
235
243
|
ethos: row.ethos || undefined,
|
|
236
244
|
version: row.version,
|
|
@@ -238,18 +246,21 @@ class SiduriDatabase {
|
|
|
238
246
|
};
|
|
239
247
|
}
|
|
240
248
|
setIdentity(identity) {
|
|
249
|
+
const role = identity.role || identity.archetype || null;
|
|
250
|
+
const archetype = identity.archetype || identity.role || null;
|
|
241
251
|
const stmt = this.db.prepare(`
|
|
242
|
-
INSERT INTO self_identity (companion_id, name, archetype, origin, ethos, version, updated_at)
|
|
243
|
-
VALUES (?, ?, ?, ?, ?, ?, datetime('now'))
|
|
252
|
+
INSERT INTO self_identity (companion_id, name, archetype, role, origin, ethos, version, updated_at)
|
|
253
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
244
254
|
ON CONFLICT(companion_id) DO UPDATE SET
|
|
245
255
|
name = excluded.name,
|
|
246
256
|
archetype = excluded.archetype,
|
|
257
|
+
role = excluded.role,
|
|
247
258
|
origin = excluded.origin,
|
|
248
259
|
ethos = excluded.ethos,
|
|
249
260
|
version = excluded.version,
|
|
250
261
|
updated_at = datetime('now')
|
|
251
262
|
`);
|
|
252
|
-
stmt.run(identity.companionId, identity.name,
|
|
263
|
+
stmt.run(identity.companionId, identity.name, archetype, role, identity.origin || null, identity.ethos || null, identity.version);
|
|
253
264
|
}
|
|
254
265
|
getPersonality(companionId) {
|
|
255
266
|
const stmt = this.db.prepare('SELECT * FROM self_personality WHERE companion_id = ?');
|
|
@@ -311,6 +322,14 @@ class SiduriDatabase {
|
|
|
311
322
|
const stmt = this.db.prepare(`
|
|
312
323
|
INSERT INTO self_directives (id, companion_id, priority, directive, status, category, scope_actor, supersedes_id, created_at)
|
|
313
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
|
|
314
333
|
`);
|
|
315
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());
|
|
316
335
|
}
|
|
@@ -332,6 +351,9 @@ class SiduriDatabase {
|
|
|
332
351
|
return;
|
|
333
352
|
}
|
|
334
353
|
if (normalizeStatus(row.status) !== 'pending') {
|
|
354
|
+
if (normalizeStatus(row.status) === 'active') {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
335
357
|
throw new Error(`Cannot approve directive '${id}': invalid transition from status '${row.status}' to 'active' (only pending directives can be approved)`);
|
|
336
358
|
}
|
|
337
359
|
// If this directive supersedes an earlier directive, transition that prior directive to superseded
|
|
@@ -407,8 +429,10 @@ class SiduriDatabase {
|
|
|
407
429
|
}
|
|
408
430
|
}
|
|
409
431
|
getRelationship(companionId, entityId) {
|
|
410
|
-
const
|
|
411
|
-
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);
|
|
412
436
|
if (!row)
|
|
413
437
|
return undefined;
|
|
414
438
|
return {
|
|
@@ -636,7 +660,7 @@ class SiduriDatabase {
|
|
|
636
660
|
INSERT INTO memory_claims (id, companion_id, subject, predicate, value, status, confidence, valid_from, valid_until, evidence, asserted_at, supersedes, source_event_id)
|
|
637
661
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, coalesce(?, datetime('now')), ?, ?)
|
|
638
662
|
`);
|
|
639
|
-
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);
|
|
640
664
|
return {
|
|
641
665
|
...claim,
|
|
642
666
|
id,
|
|
@@ -656,6 +680,9 @@ class SiduriDatabase {
|
|
|
656
680
|
return;
|
|
657
681
|
}
|
|
658
682
|
if (normalizeStatus(row.status) !== 'pending') {
|
|
683
|
+
if (normalizeStatus(row.status) === 'approved') {
|
|
684
|
+
return;
|
|
685
|
+
}
|
|
659
686
|
throw new Error(`Cannot approve claim '${id}': invalid transition from status '${row.status}' to 'approved' (only pending claims can be approved)`);
|
|
660
687
|
}
|
|
661
688
|
// If this claim supersedes an earlier claim, transition that prior claim to superseded
|
|
@@ -678,6 +705,94 @@ class SiduriDatabase {
|
|
|
678
705
|
const stmt = this.db.prepare("UPDATE memory_claims SET status = 'approved' WHERE id = ? AND LOWER(status) = 'pending'");
|
|
679
706
|
stmt.run(id);
|
|
680
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
|
+
}
|
|
681
796
|
}
|
|
682
797
|
rejectClaim(id, companionId) {
|
|
683
798
|
if (companionId) {
|
package/dist/siduri-db.test.js
CHANGED
|
@@ -730,7 +730,8 @@ describe('SiduriDatabase', () => {
|
|
|
730
730
|
status: 'active',
|
|
731
731
|
category: 'behavioral',
|
|
732
732
|
});
|
|
733
|
-
|
|
733
|
+
// Approving an already-active directive is now idempotent (no-op, does not throw)
|
|
734
|
+
expect(() => db.approveDirective('dir-active-1')).not.toThrow();
|
|
734
735
|
// 3. Rejecting an already ACTIVE directive throws
|
|
735
736
|
expect(() => db.rejectDirective('dir-active-1')).toThrow(/invalid transition from status 'active' to 'rejected'/i);
|
|
736
737
|
});
|
package/dist/teaching.js
CHANGED
|
@@ -20,12 +20,20 @@ function extractDeterministicTeaching(message, context, sourceEventId) {
|
|
|
20
20
|
if (!text) {
|
|
21
21
|
return { claims, behaviorProposals };
|
|
22
22
|
}
|
|
23
|
-
const
|
|
24
|
-
const
|
|
23
|
+
const rawActorId = context?.actor?.actorId;
|
|
24
|
+
const cleanActorId = rawActorId ? rawActorId.replace(/^actor:/, '') : undefined;
|
|
25
|
+
const actorSubject = cleanActorId ? `actor:${cleanActorId}` : 'actor:anonymous';
|
|
25
26
|
const companionId = context?.companionId || 'default';
|
|
26
27
|
const sensitivity = context?.conversation?.channel === 'public' ? 'public' : 'private';
|
|
28
|
+
// Strip leading companion addressing: "Siduri, you are...", "Hey Siduri: ..."
|
|
29
|
+
const cleanText = text.replace(/^(?:(?:hey|hi|hello)\s+)?(?:siduri|companion|assistant)\s*[,:]\s*/i, '');
|
|
30
|
+
const isTeachMode = context?.mode === 'teach' || /^(?:!teach|\/teach|\bteach mode\b|\blearn this rule\b)/i.test(text);
|
|
31
|
+
const hasExplicitTeachingCue = isTeachMode ||
|
|
32
|
+
/\b(?:remember that|remember this rule|remember this|from now on|learn this|rule:)\b/i.test(text);
|
|
33
|
+
// Casual banter / hedged opinion filter to avoid mutating Self from generic conversation
|
|
34
|
+
const isCasualBanter = /\b(?:probably|maybe|such a|so |very |really |just |not |the funniest|the best|the worst|the coolest|great|awesome|funny|nice|kind|crazy|wrong|right|silly)\b/i;
|
|
27
35
|
// 1. Companion's Name: "your name is X" / "you are called X"
|
|
28
|
-
const companionNameMatch =
|
|
36
|
+
const companionNameMatch = cleanText.match(/\b(?:your name is|you are called)\s+(.+?)(?=\s+and\s+(?:i\b|my\b|you\b)|[.;,]|$)/i);
|
|
29
37
|
if (companionNameMatch) {
|
|
30
38
|
const name = cleanValue(companionNameMatch[1], 80);
|
|
31
39
|
claims.push({
|
|
@@ -45,12 +53,124 @@ function extractDeterministicTeaching(message, context, sourceEventId) {
|
|
|
45
53
|
predicate: 'name',
|
|
46
54
|
value: name,
|
|
47
55
|
memoryClass: 'identity',
|
|
56
|
+
category: 'relational',
|
|
48
57
|
sourceEventId,
|
|
49
58
|
});
|
|
50
59
|
}
|
|
51
|
-
// 2.
|
|
52
|
-
|
|
53
|
-
|
|
60
|
+
// 2. Identity / Role Teaching:
|
|
61
|
+
// "your role is X", "you work at X", "you were created by X", "you are from X",
|
|
62
|
+
// or explicit "you are [an/a] X [at Y]" when in teach mode or with explicit teaching cues
|
|
63
|
+
const roleMatch = cleanText.match(/\byour role is\s+(.+?)(?=\s+and\s+(?:i\b|my\b|you\b)|[.;,]|$)/i);
|
|
64
|
+
const workMatch = cleanText.match(/\byou work (?:at|for)\s+(.+?)(?=\s+and\s+(?:i\b|my\b|you\b)|[.;,]|$)/i);
|
|
65
|
+
const createdByMatch = cleanText.match(/\byou (?:were|are) created by\s+(.+?)(?=\s+and\s+(?:i\b|my\b|you\b)|[.;,]|$)/i);
|
|
66
|
+
const fromMatch = cleanText.match(/\byou are from\s+(.+?)(?=\s+and\s+(?:i\b|my\b|you\b)|[.;,]|$)/i);
|
|
67
|
+
// Match "you are [an/a/the] X [at Y]" only when in Teach mode or explicit teaching cues, and not casual banter
|
|
68
|
+
const youAreMatch = (isTeachMode || hasExplicitTeachingCue)
|
|
69
|
+
? cleanText.match(/\b(?:remember that\s+)?you are\s+(?:(?:an?|the)\s+)?(.+?)(?=\s+and\s+(?:i\b|my\b|you\b)|[.;,]|$)/i)
|
|
70
|
+
: null;
|
|
71
|
+
const validYouAreRole = youAreMatch &&
|
|
72
|
+
!companionNameMatch &&
|
|
73
|
+
!fromMatch &&
|
|
74
|
+
!isCasualBanter.test(youAreMatch[1]) &&
|
|
75
|
+
!/^(?:called|named)\b/i.test(youAreMatch[1])
|
|
76
|
+
? cleanValue(youAreMatch[1].replace(/^(?:an?|the)\s+/i, ''), 100)
|
|
77
|
+
: undefined;
|
|
78
|
+
const rawEffectiveRole = roleMatch ? cleanValue(roleMatch[1], 100) : validYouAreRole;
|
|
79
|
+
const effectiveRole = rawEffectiveRole ? rawEffectiveRole.replace(/^(?:an?|the)\s+/i, '') : undefined;
|
|
80
|
+
if (effectiveRole) {
|
|
81
|
+
claims.push({
|
|
82
|
+
subject: `companion:${companionId}`,
|
|
83
|
+
predicate: 'role',
|
|
84
|
+
value: effectiveRole,
|
|
85
|
+
content: `The companion's role is ${effectiveRole}.`,
|
|
86
|
+
claimType: 'semantic',
|
|
87
|
+
provenance: 'deterministic_teaching',
|
|
88
|
+
sensitivity: 'public',
|
|
89
|
+
sourceEventId,
|
|
90
|
+
});
|
|
91
|
+
behaviorProposals.push({
|
|
92
|
+
directive: `Acknowledge role as ${effectiveRole}`,
|
|
93
|
+
priority: 70,
|
|
94
|
+
subject: `companion:${companionId}`,
|
|
95
|
+
predicate: 'role',
|
|
96
|
+
value: effectiveRole,
|
|
97
|
+
memoryClass: 'identity',
|
|
98
|
+
category: 'relational',
|
|
99
|
+
sourceEventId,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (workMatch) {
|
|
103
|
+
const workplace = cleanValue(workMatch[1], 80);
|
|
104
|
+
claims.push({
|
|
105
|
+
subject: `companion:${companionId}`,
|
|
106
|
+
predicate: 'origin',
|
|
107
|
+
value: workplace,
|
|
108
|
+
content: `The companion works at ${workplace}.`,
|
|
109
|
+
claimType: 'semantic',
|
|
110
|
+
provenance: 'deterministic_teaching',
|
|
111
|
+
sensitivity: 'public',
|
|
112
|
+
sourceEventId,
|
|
113
|
+
});
|
|
114
|
+
behaviorProposals.push({
|
|
115
|
+
directive: `Acknowledge workplace as ${workplace}`,
|
|
116
|
+
priority: 70,
|
|
117
|
+
subject: `companion:${companionId}`,
|
|
118
|
+
predicate: 'origin',
|
|
119
|
+
value: workplace,
|
|
120
|
+
memoryClass: 'identity',
|
|
121
|
+
category: 'relational',
|
|
122
|
+
sourceEventId,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
if (createdByMatch) {
|
|
126
|
+
const creator = cleanValue(createdByMatch[1], 80);
|
|
127
|
+
claims.push({
|
|
128
|
+
subject: `companion:${companionId}`,
|
|
129
|
+
predicate: 'created_by',
|
|
130
|
+
value: creator,
|
|
131
|
+
content: `The companion was created by ${creator}.`,
|
|
132
|
+
claimType: 'semantic',
|
|
133
|
+
provenance: 'deterministic_teaching',
|
|
134
|
+
sensitivity: 'public',
|
|
135
|
+
sourceEventId,
|
|
136
|
+
});
|
|
137
|
+
behaviorProposals.push({
|
|
138
|
+
directive: `Acknowledge creator as ${creator}`,
|
|
139
|
+
priority: 75,
|
|
140
|
+
subject: `companion:${companionId}`,
|
|
141
|
+
predicate: 'created_by',
|
|
142
|
+
value: creator,
|
|
143
|
+
memoryClass: 'identity',
|
|
144
|
+
category: 'relational',
|
|
145
|
+
sourceEventId,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
if (fromMatch) {
|
|
149
|
+
const origin = cleanValue(fromMatch[1], 80);
|
|
150
|
+
claims.push({
|
|
151
|
+
subject: `companion:${companionId}`,
|
|
152
|
+
predicate: 'origin',
|
|
153
|
+
value: origin,
|
|
154
|
+
content: `The companion is from ${origin}.`,
|
|
155
|
+
claimType: 'semantic',
|
|
156
|
+
provenance: 'deterministic_teaching',
|
|
157
|
+
sensitivity: 'public',
|
|
158
|
+
sourceEventId,
|
|
159
|
+
});
|
|
160
|
+
behaviorProposals.push({
|
|
161
|
+
directive: `Acknowledge origin as ${origin}`,
|
|
162
|
+
priority: 70,
|
|
163
|
+
subject: `companion:${companionId}`,
|
|
164
|
+
predicate: 'origin',
|
|
165
|
+
value: origin,
|
|
166
|
+
memoryClass: 'identity',
|
|
167
|
+
category: 'relational',
|
|
168
|
+
sourceEventId,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
// 3. Actor's Name: "my name is X"
|
|
172
|
+
const myNameMatch = cleanText.match(/\bmy name is\s+(.+?)(?=\s+and\s+(?:i\b|my\b|you\b)|[.;,]|$)/i);
|
|
173
|
+
if (myNameMatch && !/\b(?:private|public|everywhere)\b/i.test(cleanText)) {
|
|
54
174
|
const name = cleanValue(myNameMatch[1], 80);
|
|
55
175
|
claims.push({
|
|
56
176
|
subject: actorSubject,
|
|
@@ -63,8 +183,8 @@ function extractDeterministicTeaching(message, context, sourceEventId) {
|
|
|
63
183
|
sourceEventId,
|
|
64
184
|
});
|
|
65
185
|
}
|
|
66
|
-
//
|
|
67
|
-
const callMeMatch =
|
|
186
|
+
// 4. Preferred Address / Call me X: "call me X"
|
|
187
|
+
const callMeMatch = cleanText.match(/\b(?:(?:from now on|only),?\s*)?call me\s+(.+?)(?:\s+(?:in private|privately|in public|publicly|everywhere|in direct conversations))?(?=\s+and\s+(?:i\b|my\b|you\b)|[.;,]|$)/i);
|
|
68
188
|
if (callMeMatch) {
|
|
69
189
|
const address = cleanValue(callMeMatch[1], 80);
|
|
70
190
|
const directiveInstruction = `Address ${actorSubject} as ${address}`;
|
|
@@ -85,13 +205,15 @@ function extractDeterministicTeaching(message, context, sourceEventId) {
|
|
|
85
205
|
predicate: 'preferred_address',
|
|
86
206
|
value: address,
|
|
87
207
|
memoryClass: 'behavioral',
|
|
208
|
+
category: 'behavioral',
|
|
88
209
|
sourceEventId,
|
|
89
210
|
});
|
|
90
211
|
}
|
|
91
|
-
//
|
|
92
|
-
const relMatch =
|
|
212
|
+
// 5. Stated relationship: "I am your creator, Kur Zagin" / "I am your X" / "I'm your creator"
|
|
213
|
+
const relMatch = cleanText.match(/\b(?:i am|i'm)\s+your\s+([A-Za-z0-9_-]+)(?:,\s*([A-Za-z0-9_\s-]+?))?(?=\s+and\s+(?:i\b|my\b|you\b)|[.;]|$)/i);
|
|
93
214
|
if (relMatch) {
|
|
94
215
|
const relationship = cleanValue(relMatch[1], 60);
|
|
216
|
+
const actorName = relMatch[2] ? cleanValue(relMatch[2], 80) : undefined;
|
|
95
217
|
claims.push({
|
|
96
218
|
subject: actorSubject,
|
|
97
219
|
predicate: 'stated_relationship',
|
|
@@ -109,11 +231,78 @@ function extractDeterministicTeaching(message, context, sourceEventId) {
|
|
|
109
231
|
predicate: 'stated_relationship',
|
|
110
232
|
value: relationship,
|
|
111
233
|
memoryClass: 'relationship',
|
|
234
|
+
category: 'relational',
|
|
235
|
+
sourceEventId,
|
|
236
|
+
});
|
|
237
|
+
if (actorName) {
|
|
238
|
+
claims.push({
|
|
239
|
+
subject: actorSubject,
|
|
240
|
+
predicate: 'name',
|
|
241
|
+
value: actorName,
|
|
242
|
+
content: `The actor's name is ${actorName}.`,
|
|
243
|
+
claimType: 'preference',
|
|
244
|
+
provenance: 'deterministic_teaching',
|
|
245
|
+
sensitivity,
|
|
246
|
+
sourceEventId,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// 6. Behavioral rule / directive: "Remember this rule: X" / "Remember that rule: X" / "Rule: X" / "From now on, always X"
|
|
251
|
+
const ruleMatch = cleanText.match(/\b(?:remember\s+(?:this|that)\s+rule:\s*|rule:\s*|(?:from now on,?\s+)?always\s+)(.+?)(?=\s+and\s+(?:i\b|my\b|you\b)|[.;]|$)/i);
|
|
252
|
+
if (ruleMatch) {
|
|
253
|
+
let instruction = cleanValue(ruleMatch[1], 160);
|
|
254
|
+
if (instruction) {
|
|
255
|
+
instruction = instruction.charAt(0).toUpperCase() + instruction.slice(1);
|
|
256
|
+
behaviorProposals.push({
|
|
257
|
+
directive: instruction,
|
|
258
|
+
priority: 60,
|
|
259
|
+
subject: actorSubject,
|
|
260
|
+
predicate: 'rule',
|
|
261
|
+
value: instruction,
|
|
262
|
+
category: 'behavioral',
|
|
263
|
+
memoryClass: 'behavioral',
|
|
264
|
+
sourceEventId,
|
|
265
|
+
});
|
|
266
|
+
claims.push({
|
|
267
|
+
subject: actorSubject,
|
|
268
|
+
predicate: 'behavioral_rule',
|
|
269
|
+
value: instruction,
|
|
270
|
+
content: `Behavioral rule: ${instruction}`,
|
|
271
|
+
claimType: 'preference',
|
|
272
|
+
provenance: 'deterministic_teaching',
|
|
273
|
+
sensitivity,
|
|
274
|
+
sourceEventId,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// Preference: "I prefer concise answers"
|
|
279
|
+
const prefAnswersMatch = cleanText.match(/\b(?:i prefer|my preference is)\s+(.+?)(?=\s+and\s+(?:i\b|my\b|you\b)|[.;,]|$)/i);
|
|
280
|
+
if (prefAnswersMatch && !cleanText.match(/\bmy\s+preferred\s+([A-Za-z0-9_]+)\s+is\b/i)) {
|
|
281
|
+
const prefVal = cleanValue(prefAnswersMatch[1], 100);
|
|
282
|
+
const directive = `Prefer ${prefVal}`;
|
|
283
|
+
behaviorProposals.push({
|
|
284
|
+
directive,
|
|
285
|
+
priority: 60,
|
|
286
|
+
subject: actorSubject,
|
|
287
|
+
predicate: 'preference',
|
|
288
|
+
value: prefVal,
|
|
289
|
+
category: 'behavioral',
|
|
290
|
+
memoryClass: 'behavioral',
|
|
291
|
+
sourceEventId,
|
|
292
|
+
});
|
|
293
|
+
claims.push({
|
|
294
|
+
subject: actorSubject,
|
|
295
|
+
predicate: 'preference',
|
|
296
|
+
value: prefVal,
|
|
297
|
+
content: `The actor prefers ${prefVal}.`,
|
|
298
|
+
claimType: 'preference',
|
|
299
|
+
provenance: 'deterministic_teaching',
|
|
300
|
+
sensitivity,
|
|
112
301
|
sourceEventId,
|
|
113
302
|
});
|
|
114
303
|
}
|
|
115
|
-
//
|
|
116
|
-
const prefMatch =
|
|
304
|
+
// 7. Explicit Domain / Preference fact: "my preferred X is Y" / "my X is Y"
|
|
305
|
+
const prefMatch = cleanText.match(/\bmy\s+preferred\s+([A-Za-z0-9_]+)\s+is\s+(.+?)(?=\s+and\s+(?:i\b|my\b|you\b)|[.;,]|$)/i);
|
|
117
306
|
if (prefMatch) {
|
|
118
307
|
const predicate = cleanValue(prefMatch[1], 40);
|
|
119
308
|
const val = cleanValue(prefMatch[2], 100);
|
package/package.json
CHANGED