@siduri-x/core 2.0.5 → 2.0.6
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/conversational-teach.test.js +177 -47
- package/dist/intent-classifier.js +2 -2
- package/dist/perception-cycle.test.js +14 -0
- package/dist/prompt-compiler.js +1 -1
- package/dist/runtime.js +39 -9
- package/dist/siduri-db.d.ts +2 -0
- package/dist/siduri-db.js +60 -14
- package/dist/teaching.d.ts +6 -7
- package/dist/teaching.js +7 -314
- package/package.json +1 -1
|
@@ -124,7 +124,8 @@ describe('Conversational Teach Mode End-to-End Lifecycle', () => {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
if (ctx.relationship) {
|
|
127
|
-
|
|
127
|
+
const nameStr = ctx.relationship.name ? ` [Name: ${ctx.relationship.name}]` : '';
|
|
128
|
+
parts.push(`Relationship Stance:\n- Stance toward ${ctx.relationship.entityId}${nameStr}: ${ctx.relationship.stance} (Role: ${ctx.relationship.role})`);
|
|
128
129
|
}
|
|
129
130
|
if (ctx.directives && ctx.directives.length > 0) {
|
|
130
131
|
parts.push(`Behavioral Directives:\n${ctx.directives.map((d) => `- ${d.directive}`).join('\n')}`);
|
|
@@ -150,6 +151,106 @@ describe('Conversational Teach Mode End-to-End Lifecycle', () => {
|
|
|
150
151
|
},
|
|
151
152
|
};
|
|
152
153
|
}
|
|
154
|
+
function createCognitiveMockBrain(companionId) {
|
|
155
|
+
return {
|
|
156
|
+
generatePlan: jest.fn().mockImplementation(async (brainCtx) => {
|
|
157
|
+
const lastMsg = brainCtx.recentMessages?.[brainCtx.recentMessages.length - 1]?.content || '';
|
|
158
|
+
const memoryProposals = [];
|
|
159
|
+
const behaviorProposals = [];
|
|
160
|
+
if (/AI researcher at VXNUS Studio/i.test(lastMsg)) {
|
|
161
|
+
memoryProposals.push({
|
|
162
|
+
subject: `companion:${companionId}`,
|
|
163
|
+
predicate: 'role',
|
|
164
|
+
value: 'AI researcher at VXNUS Studio',
|
|
165
|
+
});
|
|
166
|
+
behaviorProposals.push({
|
|
167
|
+
directive: 'Acknowledge role as AI researcher at VXNUS Studio',
|
|
168
|
+
category: 'relational',
|
|
169
|
+
subject: `companion:${companionId}`,
|
|
170
|
+
predicate: 'role',
|
|
171
|
+
value: 'AI researcher at VXNUS Studio',
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
else if (/Lead Architect at VXNUS Studio/i.test(lastMsg)) {
|
|
175
|
+
memoryProposals.push({
|
|
176
|
+
subject: `companion:${companionId}`,
|
|
177
|
+
predicate: 'role',
|
|
178
|
+
value: 'Lead Architect at VXNUS Studio',
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
else if (/Research Specialist/i.test(lastMsg)) {
|
|
182
|
+
memoryProposals.push({
|
|
183
|
+
subject: `companion:${companionId}`,
|
|
184
|
+
predicate: 'role',
|
|
185
|
+
value: 'Research Specialist',
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
else if (/Security Officer/i.test(lastMsg)) {
|
|
189
|
+
memoryProposals.push({
|
|
190
|
+
subject: `companion:${companionId}`,
|
|
191
|
+
predicate: 'role',
|
|
192
|
+
value: 'Security Officer',
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
else if (/VXNUS Studio Staff/i.test(lastMsg)) {
|
|
196
|
+
memoryProposals.push({
|
|
197
|
+
subject: `companion:${companionId}`,
|
|
198
|
+
predicate: 'role',
|
|
199
|
+
value: 'VXNUS Studio Staff',
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
if (/\bcreator\b/i.test(lastMsg)) {
|
|
203
|
+
memoryProposals.push({
|
|
204
|
+
subject: 'actor:kur-zagin',
|
|
205
|
+
predicate: 'stated_relationship',
|
|
206
|
+
value: 'creator',
|
|
207
|
+
claimType: 'relationship',
|
|
208
|
+
});
|
|
209
|
+
behaviorProposals.push({
|
|
210
|
+
directive: 'Recognize actor:kur-zagin stated relationship as creator',
|
|
211
|
+
category: 'relational',
|
|
212
|
+
subject: 'actor:kur-zagin',
|
|
213
|
+
predicate: 'stated_relationship',
|
|
214
|
+
value: 'creator',
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
if (/Kur Zagin/i.test(lastMsg)) {
|
|
218
|
+
memoryProposals.push({
|
|
219
|
+
subject: 'actor:kur-zagin',
|
|
220
|
+
predicate: 'name',
|
|
221
|
+
value: 'Kur Zagin',
|
|
222
|
+
claimType: 'preference',
|
|
223
|
+
});
|
|
224
|
+
behaviorProposals.push({
|
|
225
|
+
directive: 'Address actor:kur-zagin as Kur Zagin',
|
|
226
|
+
category: 'relational',
|
|
227
|
+
subject: 'actor:kur-zagin',
|
|
228
|
+
predicate: 'name',
|
|
229
|
+
value: 'Kur Zagin',
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
if (/be concise when answering technical questions/i.test(lastMsg)) {
|
|
233
|
+
behaviorProposals.push({
|
|
234
|
+
directive: 'Be concise when answering technical questions',
|
|
235
|
+
category: 'behavioral',
|
|
236
|
+
priority: 60,
|
|
237
|
+
});
|
|
238
|
+
memoryProposals.push({
|
|
239
|
+
subject: 'actor:kur-zagin',
|
|
240
|
+
predicate: 'rule',
|
|
241
|
+
value: 'Be concise when answering technical questions',
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
return {
|
|
245
|
+
speech: 'Understood, I have acknowledged your input.',
|
|
246
|
+
language: 'en',
|
|
247
|
+
memoryProposals: memoryProposals.length > 0 ? memoryProposals : undefined,
|
|
248
|
+
behaviorProposals: behaviorProposals.length > 0 ? behaviorProposals : undefined,
|
|
249
|
+
_receivedSystemPrompt: brainCtx.systemPrompt,
|
|
250
|
+
};
|
|
251
|
+
}),
|
|
252
|
+
};
|
|
253
|
+
}
|
|
153
254
|
// =========================================================================
|
|
154
255
|
// Test A: Conversational role teaching in Teach mode
|
|
155
256
|
// =========================================================================
|
|
@@ -159,16 +260,7 @@ describe('Conversational Teach Mode End-to-End Lifecycle', () => {
|
|
|
159
260
|
const self = createSelfRepository(db);
|
|
160
261
|
const memory = createMemoryOrgan(db);
|
|
161
262
|
const behavior = createBehaviorCompiler();
|
|
162
|
-
const mockBrain =
|
|
163
|
-
generatePlan: jest.fn().mockImplementation(async (brainCtx) => {
|
|
164
|
-
return {
|
|
165
|
-
speech: 'Understood, I have acknowledged my role.',
|
|
166
|
-
language: 'en',
|
|
167
|
-
// Brain context should have received the system prompt
|
|
168
|
-
_receivedSystemPrompt: brainCtx.systemPrompt,
|
|
169
|
-
};
|
|
170
|
-
}),
|
|
171
|
-
};
|
|
263
|
+
const mockBrain = createCognitiveMockBrain(companionId);
|
|
172
264
|
const runtime = new index_1.SiduriRuntime(companionId, { name: 'Siduri' }, {
|
|
173
265
|
brain: mockBrain,
|
|
174
266
|
memory,
|
|
@@ -227,12 +319,7 @@ describe('Conversational Teach Mode End-to-End Lifecycle', () => {
|
|
|
227
319
|
const self = createSelfRepository(db);
|
|
228
320
|
const memory = createMemoryOrgan(db);
|
|
229
321
|
const behavior = createBehaviorCompiler();
|
|
230
|
-
const mockBrain =
|
|
231
|
-
generatePlan: jest.fn().mockResolvedValue({
|
|
232
|
-
speech: 'Greetings, Creator.',
|
|
233
|
-
language: 'en',
|
|
234
|
-
}),
|
|
235
|
-
};
|
|
322
|
+
const mockBrain = createCognitiveMockBrain(companionId);
|
|
236
323
|
const runtime = new index_1.SiduriRuntime(companionId, { name: 'Siduri' }, {
|
|
237
324
|
brain: mockBrain,
|
|
238
325
|
memory,
|
|
@@ -282,12 +369,7 @@ describe('Conversational Teach Mode End-to-End Lifecycle', () => {
|
|
|
282
369
|
const self = createSelfRepository(db);
|
|
283
370
|
const memory = createMemoryOrgan(db);
|
|
284
371
|
const behavior = createBehaviorCompiler();
|
|
285
|
-
const mockBrain =
|
|
286
|
-
generatePlan: jest.fn().mockResolvedValue({
|
|
287
|
-
speech: 'Rule noted.',
|
|
288
|
-
language: 'en',
|
|
289
|
-
}),
|
|
290
|
-
};
|
|
372
|
+
const mockBrain = createCognitiveMockBrain(companionId);
|
|
291
373
|
const runtime = new index_1.SiduriRuntime(companionId, { name: 'Siduri' }, {
|
|
292
374
|
brain: mockBrain,
|
|
293
375
|
memory,
|
|
@@ -370,12 +452,7 @@ describe('Conversational Teach Mode End-to-End Lifecycle', () => {
|
|
|
370
452
|
const companionId = 'comp-test-e';
|
|
371
453
|
const self = createSelfRepository(db);
|
|
372
454
|
const memory = createMemoryOrgan(db);
|
|
373
|
-
const mockBrain =
|
|
374
|
-
generatePlan: jest.fn().mockResolvedValue({
|
|
375
|
-
speech: 'Understood.',
|
|
376
|
-
language: 'en',
|
|
377
|
-
}),
|
|
378
|
-
};
|
|
455
|
+
const mockBrain = createCognitiveMockBrain(companionId);
|
|
379
456
|
const runtime = new index_1.SiduriRuntime(companionId, { name: 'Siduri' }, {
|
|
380
457
|
brain: mockBrain,
|
|
381
458
|
memory,
|
|
@@ -408,12 +485,7 @@ describe('Conversational Teach Mode End-to-End Lifecycle', () => {
|
|
|
408
485
|
const db1 = new index_1.SiduriDatabase({ dbPath });
|
|
409
486
|
const self1 = createSelfRepository(db1);
|
|
410
487
|
const memory1 = createMemoryOrgan(db1);
|
|
411
|
-
const mockBrain1 =
|
|
412
|
-
generatePlan: jest.fn().mockResolvedValue({
|
|
413
|
-
speech: 'I have recorded my new role as Lead Architect.',
|
|
414
|
-
language: 'en',
|
|
415
|
-
}),
|
|
416
|
-
};
|
|
488
|
+
const mockBrain1 = createCognitiveMockBrain(companionId);
|
|
417
489
|
const runtime1 = new index_1.SiduriRuntime(companionId, { name: 'Siduri' }, {
|
|
418
490
|
brain: mockBrain1,
|
|
419
491
|
memory: memory1,
|
|
@@ -440,12 +512,7 @@ describe('Conversational Teach Mode End-to-End Lifecycle', () => {
|
|
|
440
512
|
const self2 = createSelfRepository(db2);
|
|
441
513
|
const memory2 = createMemoryOrgan(db2);
|
|
442
514
|
const behavior2 = createBehaviorCompiler();
|
|
443
|
-
const mockBrain2 =
|
|
444
|
-
generatePlan: jest.fn().mockResolvedValue({
|
|
445
|
-
speech: 'Ready to build architecture.',
|
|
446
|
-
language: 'en',
|
|
447
|
-
}),
|
|
448
|
-
};
|
|
515
|
+
const mockBrain2 = createCognitiveMockBrain(companionId);
|
|
449
516
|
const runtime2 = new index_1.SiduriRuntime(companionId, { name: 'Siduri' }, {
|
|
450
517
|
brain: mockBrain2,
|
|
451
518
|
memory: memory2,
|
|
@@ -477,12 +544,7 @@ describe('Conversational Teach Mode End-to-End Lifecycle', () => {
|
|
|
477
544
|
const companionId = 'comp-test-g';
|
|
478
545
|
const self = createSelfRepository(db);
|
|
479
546
|
const memory = createMemoryOrgan(db);
|
|
480
|
-
const mockBrain =
|
|
481
|
-
generatePlan: jest.fn().mockResolvedValue({
|
|
482
|
-
speech: 'Understood.',
|
|
483
|
-
language: 'en',
|
|
484
|
-
}),
|
|
485
|
-
};
|
|
547
|
+
const mockBrain = createCognitiveMockBrain(companionId);
|
|
486
548
|
const runtime = new index_1.SiduriRuntime(companionId, { name: 'Siduri' }, {
|
|
487
549
|
brain: mockBrain,
|
|
488
550
|
memory,
|
|
@@ -510,4 +572,72 @@ describe('Conversational Teach Mode End-to-End Lifecycle', () => {
|
|
|
510
572
|
expect(roleDirectives).toHaveLength(1);
|
|
511
573
|
db.close();
|
|
512
574
|
});
|
|
575
|
+
// =========================================================================
|
|
576
|
+
// Test H: Natural conversational teaching (past-tense role, user name, creator)
|
|
577
|
+
// =========================================================================
|
|
578
|
+
it('Test H: teaches companion past role ("she was VXNUS Studio Staff"), creator, and name, then recognizes user on subsequent turn', async () => {
|
|
579
|
+
const db = new index_1.SiduriDatabase({ dbPath });
|
|
580
|
+
const companionId = 'comp-test-h';
|
|
581
|
+
const self = createSelfRepository(db);
|
|
582
|
+
const memory = createMemoryOrgan(db);
|
|
583
|
+
const behavior = createBehaviorCompiler();
|
|
584
|
+
const mockBrain = createCognitiveMockBrain(companionId);
|
|
585
|
+
const runtime = new index_1.SiduriRuntime(companionId, { name: 'Siduri' }, {
|
|
586
|
+
brain: mockBrain,
|
|
587
|
+
memory,
|
|
588
|
+
self,
|
|
589
|
+
behavior,
|
|
590
|
+
});
|
|
591
|
+
await runtime.initialize();
|
|
592
|
+
// 1. "she was VXNUS Studio Staff" in Teach mode
|
|
593
|
+
const resRole = await runtime.processPerception({
|
|
594
|
+
source: 'text_chat',
|
|
595
|
+
text: 'She was VXNUS Studio Staff.',
|
|
596
|
+
context: createRequestContext(companionId, 'teach', 'actor:kur-zagin'),
|
|
597
|
+
});
|
|
598
|
+
expect(resRole.status).toBe('APPROVED');
|
|
599
|
+
const roleProp = resRole.metadata?.proposals?.find((p) => p.predicate === 'role');
|
|
600
|
+
expect(roleProp).toBeDefined();
|
|
601
|
+
expect(roleProp.value).toBe('VXNUS Studio Staff');
|
|
602
|
+
await runtime.approveProposal(roleProp.id, { companionId });
|
|
603
|
+
// 2. "my name is Kur Zagin" in Teach mode
|
|
604
|
+
const resName = await runtime.processPerception({
|
|
605
|
+
source: 'text_chat',
|
|
606
|
+
text: 'My name is Kur Zagin.',
|
|
607
|
+
context: createRequestContext(companionId, 'teach', 'actor:kur-zagin'),
|
|
608
|
+
});
|
|
609
|
+
expect(resName.status).toBe('APPROVED');
|
|
610
|
+
const nameProp = resName.metadata?.proposals?.find((p) => p.predicate === 'name');
|
|
611
|
+
expect(nameProp).toBeDefined();
|
|
612
|
+
expect(nameProp.value).toBe('Kur Zagin');
|
|
613
|
+
await runtime.approveProposal(nameProp.id, { companionId });
|
|
614
|
+
// 3. "I am your creator" in Teach mode
|
|
615
|
+
const resRel = await runtime.processPerception({
|
|
616
|
+
source: 'text_chat',
|
|
617
|
+
text: 'I am your creator.',
|
|
618
|
+
context: createRequestContext(companionId, 'teach', 'actor:kur-zagin'),
|
|
619
|
+
});
|
|
620
|
+
expect(resRel.status).toBe('APPROVED');
|
|
621
|
+
const relProp = resRel.metadata?.proposals?.find((p) => p.predicate === 'stated_relationship');
|
|
622
|
+
expect(relProp).toBeDefined();
|
|
623
|
+
await runtime.approveProposal(relProp.id, { companionId });
|
|
624
|
+
// 4. Verify Self relationship has both creator stance AND user name preserved
|
|
625
|
+
const rel = await self.getRelationship?.(companionId, 'actor:kur-zagin');
|
|
626
|
+
expect(rel).toBeDefined();
|
|
627
|
+
expect(rel?.role).toBe('creator');
|
|
628
|
+
expect(rel?.stance).toBe('familiar_loyal');
|
|
629
|
+
expect(rel?.name).toBe('Kur Zagin');
|
|
630
|
+
// 5. Subsequent conversation turn: "do you know me?"
|
|
631
|
+
await runtime.processPerception({
|
|
632
|
+
source: 'text_chat',
|
|
633
|
+
text: 'do you know me?',
|
|
634
|
+
context: createRequestContext(companionId, 'hybrid', 'actor:kur-zagin'),
|
|
635
|
+
});
|
|
636
|
+
const lastCallCtx = mockBrain.generatePlan.mock.calls[mockBrain.generatePlan.mock.calls.length - 1][0];
|
|
637
|
+
// Active Self contains both the creator stance and the user's name
|
|
638
|
+
expect(lastCallCtx.systemPrompt).toContain('Role: VXNUS Studio Staff');
|
|
639
|
+
expect(lastCallCtx.systemPrompt).toContain('familiar_loyal');
|
|
640
|
+
expect(lastCallCtx.systemPrompt).toContain('Kur Zagin');
|
|
641
|
+
db.close();
|
|
642
|
+
});
|
|
513
643
|
});
|
|
@@ -15,9 +15,9 @@ function classifyInputIntent(text, context, overrides) {
|
|
|
15
15
|
const isTeachingLike = overrides?.isTeachingLike ??
|
|
16
16
|
(explicitTeaching.claims.length > 0 ||
|
|
17
17
|
explicitTeaching.behaviorProposals.length > 0 ||
|
|
18
|
-
/\
|
|
18
|
+
/\b(?:remember that|my name is|call me)\b/i.test(normalizedMessage));
|
|
19
19
|
const isSelfIdentityRequest = overrides?.isSelfIdentityRequest ??
|
|
20
|
-
/\b(?:who|what) are you\b|\bwho is siduri\b|\b(?:your|my) name\b|\btell me about yourself\b|\bdescribe yourself\b|\bwhat is your origin\b|\bwho created you\b|\bwho made you\b|\bintroduce yourself\b/.test(normalizedMessage);
|
|
20
|
+
/\b(?:who|what) are you\b|\bwho is siduri\b|\b(?:your|my) name\b|\bdo you know me\b|\bwho am i\b|\btell me about yourself\b|\bdescribe yourself\b|\bwhat is your origin\b|\bwho created you\b|\bwho made you\b|\bintroduce yourself\b/.test(normalizedMessage);
|
|
21
21
|
const isGreeting = overrides?.isGreeting ??
|
|
22
22
|
/^(?:hello|hi|hey|greetings|good morning|good afternoon|good evening|howdy|yo)[.!]?$/.test(normalizedMessage);
|
|
23
23
|
const shouldQueryKnowledge = overrides?.shouldQueryKnowledge ??
|
|
@@ -212,6 +212,13 @@ describe('SiduriRuntime Unified Perception Cycle & Session History', () => {
|
|
|
212
212
|
generatePlan: jest.fn().mockResolvedValue({
|
|
213
213
|
speech: 'I have recorded your preferred title as Chief Engineer.',
|
|
214
214
|
language: 'en',
|
|
215
|
+
memoryProposals: [
|
|
216
|
+
{
|
|
217
|
+
subject: 'actor:alice',
|
|
218
|
+
predicate: 'preferred_address',
|
|
219
|
+
value: 'Chief Engineer',
|
|
220
|
+
},
|
|
221
|
+
],
|
|
215
222
|
}),
|
|
216
223
|
};
|
|
217
224
|
const runtime = new runtime_1.SiduriRuntime('comp-teach', { name: 'TeachBot' }, {
|
|
@@ -255,6 +262,13 @@ describe('SiduriRuntime Unified Perception Cycle & Session History', () => {
|
|
|
255
262
|
generatePlan: jest.fn().mockResolvedValue({
|
|
256
263
|
speech: 'Recorded the command.',
|
|
257
264
|
language: 'en',
|
|
265
|
+
memoryProposals: [
|
|
266
|
+
{
|
|
267
|
+
subject: 'companion:comp-infer',
|
|
268
|
+
predicate: 'name',
|
|
269
|
+
value: 'Atlas',
|
|
270
|
+
},
|
|
271
|
+
],
|
|
258
272
|
}),
|
|
259
273
|
};
|
|
260
274
|
const runtime = new runtime_1.SiduriRuntime('comp-infer', { name: 'InferBot' }, {
|
package/dist/prompt-compiler.js
CHANGED
|
@@ -49,7 +49,7 @@ async function compilePrompts(params) {
|
|
|
49
49
|
const modeInstruction = effectiveMode === 'casual'
|
|
50
50
|
? 'Operating Mode: Casual (Zero memory drift - do not attempt to persist personal claims or directives).'
|
|
51
51
|
: effectiveMode === 'teach'
|
|
52
|
-
? 'Operating Mode: Teach Mode (Active learning session -
|
|
52
|
+
? 'Operating Mode: Teach Mode (Active learning session - listen attentively to what the user shares about their identity, affiliations, relationship, or preferences, and companion identity/role. Accurately formulate candidate memoryProposals and behaviorProposals for review).'
|
|
53
53
|
: undefined;
|
|
54
54
|
const subtitleInstruction = subtitleLanguage && subtitleLanguage !== 'off'
|
|
55
55
|
? `Requested Subtitle Language: "${subtitleLanguage}". Along with your primary speech, provide a natural subtitle translation in "${subtitleLanguage}" in the subtitle field.`
|
package/dist/runtime.js
CHANGED
|
@@ -264,25 +264,55 @@ async function promoteApprovedClaimToSelf(claim, self, companionId) {
|
|
|
264
264
|
}
|
|
265
265
|
return;
|
|
266
266
|
}
|
|
267
|
-
// 2. Relationship mutations: creator or user stated relationship
|
|
267
|
+
// 2. Relationship mutations: creator or user stated relationship, name, or affiliation
|
|
268
268
|
if (claim.claimType === 'relationship' ||
|
|
269
269
|
predicate === 'stated_relationship' ||
|
|
270
270
|
predicate === 'relationship' ||
|
|
271
|
-
predicate === 'relationship_to_siduri'
|
|
271
|
+
predicate === 'relationship_to_siduri' ||
|
|
272
|
+
(predicate === 'name' && (subject.startsWith('actor:') || subject === 'user' || subject === 'primary_user')) ||
|
|
273
|
+
predicate === 'preferred_address' ||
|
|
274
|
+
predicate === 'affiliation') {
|
|
272
275
|
const rawSubject = (claim.subject || 'actor:user').replace(/^actor:actor:/, 'actor:');
|
|
273
276
|
const isCreator = value.toLowerCase() === 'creator';
|
|
277
|
+
const isName = predicate === 'name' || predicate === 'preferred_address';
|
|
278
|
+
const isAffil = predicate === 'affiliation';
|
|
279
|
+
const existingRel = typeof self.getRelationship === 'function'
|
|
280
|
+
? await self.getRelationship(targetCompanionId, rawSubject)
|
|
281
|
+
: null;
|
|
282
|
+
const role = isCreator ? value : (existingRel?.role || (isName || isAffil ? existingRel?.role : value));
|
|
283
|
+
const name = isName ? value : existingRel?.name;
|
|
284
|
+
const affiliation = isAffil ? value : existingRel?.affiliation;
|
|
285
|
+
const stance = isCreator ? 'familiar_loyal' : (existingRel?.stance || 'neutral');
|
|
286
|
+
const trustScore = isCreator ? 1.0 : (existingRel?.trustScore ?? 0.8);
|
|
287
|
+
const familiarity = isCreator ? 0.9 : (existingRel?.familiarity ?? 0.5);
|
|
288
|
+
const interactionConventions = isCreator
|
|
289
|
+
? Array.from(new Set([...(existingRel?.interactionConventions || []), 'Direct communication', 'Highest administrative trust']))
|
|
290
|
+
: (existingRel?.interactionConventions || []);
|
|
274
291
|
await self.updateRelationship(targetCompanionId, {
|
|
275
292
|
companionId: targetCompanionId,
|
|
276
293
|
entityId: rawSubject,
|
|
277
294
|
entityType: 'human',
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
295
|
+
name,
|
|
296
|
+
affiliation,
|
|
297
|
+
role,
|
|
298
|
+
stance,
|
|
299
|
+
trustScore,
|
|
300
|
+
familiarity,
|
|
301
|
+
interactionConventions,
|
|
285
302
|
});
|
|
303
|
+
if (isName) {
|
|
304
|
+
await self.commitDirectives(targetCompanionId, [
|
|
305
|
+
{
|
|
306
|
+
id: `dir-name-${claim.id || Date.now()}`,
|
|
307
|
+
companionId: targetCompanionId,
|
|
308
|
+
priority: 75,
|
|
309
|
+
directive: `Address ${rawSubject} as ${value}`,
|
|
310
|
+
status: 'active',
|
|
311
|
+
category: 'relational',
|
|
312
|
+
createdAt: new Date().toISOString(),
|
|
313
|
+
},
|
|
314
|
+
]);
|
|
315
|
+
}
|
|
286
316
|
return;
|
|
287
317
|
}
|
|
288
318
|
// 3. Behavioral rule claim
|
package/dist/siduri-db.d.ts
CHANGED
package/dist/siduri-db.js
CHANGED
|
@@ -59,6 +59,8 @@ class SiduriDatabase {
|
|
|
59
59
|
companion_id TEXT NOT NULL,
|
|
60
60
|
entity_id TEXT NOT NULL,
|
|
61
61
|
entity_type TEXT NOT NULL DEFAULT 'human',
|
|
62
|
+
name TEXT,
|
|
63
|
+
affiliation TEXT,
|
|
62
64
|
role TEXT DEFAULT 'user',
|
|
63
65
|
stance TEXT DEFAULT 'neutral',
|
|
64
66
|
trust_score REAL DEFAULT 0.5,
|
|
@@ -222,6 +224,18 @@ class SiduriDatabase {
|
|
|
222
224
|
catch {
|
|
223
225
|
// Column already exists
|
|
224
226
|
}
|
|
227
|
+
try {
|
|
228
|
+
this.db.exec("ALTER TABLE self_relationships ADD COLUMN name TEXT");
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
// Column already exists
|
|
232
|
+
}
|
|
233
|
+
try {
|
|
234
|
+
this.db.exec("ALTER TABLE self_relationships ADD COLUMN affiliation TEXT");
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
// Column already exists
|
|
238
|
+
}
|
|
225
239
|
}
|
|
226
240
|
close() {
|
|
227
241
|
this.db.close();
|
|
@@ -439,6 +453,8 @@ class SiduriDatabase {
|
|
|
439
453
|
companionId: row.companion_id,
|
|
440
454
|
entityId: row.entity_id,
|
|
441
455
|
entityType: row.entity_type || 'human',
|
|
456
|
+
name: row.name || undefined,
|
|
457
|
+
affiliation: row.affiliation || undefined,
|
|
442
458
|
role: row.role || 'user',
|
|
443
459
|
stance: row.stance || 'neutral',
|
|
444
460
|
trustScore: row.trust_score !== undefined && row.trust_score !== null ? row.trust_score : 0.5,
|
|
@@ -453,6 +469,8 @@ class SiduriDatabase {
|
|
|
453
469
|
companionId: row.companion_id,
|
|
454
470
|
entityId: row.entity_id,
|
|
455
471
|
entityType: row.entity_type || 'human',
|
|
472
|
+
name: row.name || undefined,
|
|
473
|
+
affiliation: row.affiliation || undefined,
|
|
456
474
|
role: row.role || 'user',
|
|
457
475
|
stance: row.stance || 'neutral',
|
|
458
476
|
trustScore: row.trust_score !== undefined && row.trust_score !== null ? row.trust_score : 0.5,
|
|
@@ -463,18 +481,20 @@ class SiduriDatabase {
|
|
|
463
481
|
}
|
|
464
482
|
upsertRelationship(rel) {
|
|
465
483
|
const stmt = this.db.prepare(`
|
|
466
|
-
INSERT INTO self_relationships (companion_id, entity_id, entity_type, role, stance, trust_score, familiarity, interaction_conventions, updated_at)
|
|
467
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
484
|
+
INSERT INTO self_relationships (companion_id, entity_id, entity_type, name, affiliation, role, stance, trust_score, familiarity, interaction_conventions, updated_at)
|
|
485
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, datetime('now'))
|
|
468
486
|
ON CONFLICT(companion_id, entity_id) DO UPDATE SET
|
|
469
487
|
entity_type = excluded.entity_type,
|
|
470
|
-
|
|
471
|
-
|
|
488
|
+
name = COALESCE(excluded.name, self_relationships.name),
|
|
489
|
+
affiliation = COALESCE(excluded.affiliation, self_relationships.affiliation),
|
|
490
|
+
role = COALESCE(excluded.role, self_relationships.role),
|
|
491
|
+
stance = COALESCE(excluded.stance, self_relationships.stance),
|
|
472
492
|
trust_score = excluded.trust_score,
|
|
473
493
|
familiarity = excluded.familiarity,
|
|
474
494
|
interaction_conventions = excluded.interaction_conventions,
|
|
475
495
|
updated_at = datetime('now')
|
|
476
496
|
`);
|
|
477
|
-
stmt.run(rel.companionId, rel.entityId, rel.entityType || 'human', rel.role || 'user', rel.stance || 'neutral', rel.trustScore !== undefined && rel.trustScore !== null ? rel.trustScore : 0.5, rel.familiarity !== undefined && rel.familiarity !== null ? rel.familiarity : 0.5, JSON.stringify(rel.interactionConventions || []));
|
|
497
|
+
stmt.run(rel.companionId, rel.entityId, rel.entityType || 'human', rel.name || null, rel.affiliation || null, rel.role || 'user', rel.stance || 'neutral', rel.trustScore !== undefined && rel.trustScore !== null ? rel.trustScore : 0.5, rel.familiarity !== undefined && rel.familiarity !== null ? rel.familiarity : 0.5, JSON.stringify(rel.interactionConventions || []));
|
|
478
498
|
}
|
|
479
499
|
getExemplars(companionId) {
|
|
480
500
|
const stmt = this.db.prepare('SELECT * FROM self_exemplars WHERE companion_id = ? ORDER BY created_at ASC');
|
|
@@ -760,25 +780,51 @@ class SiduriDatabase {
|
|
|
760
780
|
}
|
|
761
781
|
return;
|
|
762
782
|
}
|
|
763
|
-
// 2. Relationship mutations: creator or user stated relationship
|
|
783
|
+
// 2. Relationship mutations: creator or user stated relationship, name, or affiliation
|
|
764
784
|
if (claim.claimType === 'relationship' ||
|
|
765
785
|
predicate === 'stated_relationship' ||
|
|
766
786
|
predicate === 'relationship' ||
|
|
767
|
-
predicate === 'relationship_to_siduri'
|
|
787
|
+
predicate === 'relationship_to_siduri' ||
|
|
788
|
+
(predicate === 'name' && (subject.startsWith('actor:') || subject === 'user' || subject === 'primary_user')) ||
|
|
789
|
+
predicate === 'preferred_address' ||
|
|
790
|
+
predicate === 'affiliation') {
|
|
768
791
|
const rawSubject = (claim.subject || 'actor:user').replace(/^actor:actor:/, 'actor:');
|
|
769
792
|
const isCreator = value.toLowerCase() === 'creator';
|
|
793
|
+
const isName = predicate === 'name' || predicate === 'preferred_address';
|
|
794
|
+
const isAffil = predicate === 'affiliation';
|
|
795
|
+
const existingRel = this.getRelationship(companionId, rawSubject);
|
|
796
|
+
const role = isCreator ? value : (existingRel?.role || (isName || isAffil ? existingRel?.role : value));
|
|
797
|
+
const name = isName ? value : existingRel?.name;
|
|
798
|
+
const affiliation = isAffil ? value : existingRel?.affiliation;
|
|
799
|
+
const stance = isCreator ? 'familiar_loyal' : (existingRel?.stance || 'neutral');
|
|
800
|
+
const trustScore = isCreator ? 1.0 : (existingRel?.trustScore ?? 0.8);
|
|
801
|
+
const familiarity = isCreator ? 0.9 : (existingRel?.familiarity ?? 0.5);
|
|
802
|
+
const interactionConventions = isCreator
|
|
803
|
+
? Array.from(new Set([...(existingRel?.interactionConventions || []), 'Direct communication', 'Highest administrative trust']))
|
|
804
|
+
: (existingRel?.interactionConventions || []);
|
|
770
805
|
this.upsertRelationship({
|
|
771
806
|
companionId,
|
|
772
807
|
entityId: rawSubject,
|
|
773
808
|
entityType: 'human',
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
809
|
+
name,
|
|
810
|
+
affiliation,
|
|
811
|
+
role,
|
|
812
|
+
stance,
|
|
813
|
+
trustScore,
|
|
814
|
+
familiarity,
|
|
815
|
+
interactionConventions,
|
|
781
816
|
});
|
|
817
|
+
if (isName) {
|
|
818
|
+
this.commitDirective({
|
|
819
|
+
id: `dir-name-${claim.id || Date.now()}`,
|
|
820
|
+
companionId,
|
|
821
|
+
priority: 75,
|
|
822
|
+
directive: `Address ${rawSubject} as ${value}`,
|
|
823
|
+
status: 'active',
|
|
824
|
+
category: 'relational',
|
|
825
|
+
createdAt: new Date().toISOString(),
|
|
826
|
+
});
|
|
827
|
+
}
|
|
782
828
|
return;
|
|
783
829
|
}
|
|
784
830
|
// 3. Behavioral rule claim
|
package/dist/teaching.d.ts
CHANGED
|
@@ -4,12 +4,11 @@ export interface ExtractedTeaching {
|
|
|
4
4
|
behaviorProposals: BehaviorProposal[];
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Deterministic teaching extraction placeholder.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* - Companion identity is isolated.
|
|
9
|
+
* In Siduri-X, conversational memory and behavioral proposals are generated
|
|
10
|
+
* directly by the Brain LLM via structured cognitive planning (e.g. `submitResponsePlan`).
|
|
11
|
+
* Deterministic regex matching has been removed in favor of pure LLM comprehension,
|
|
12
|
+
* as all candidates are quarantined in 'pending' status until explicitly approved by the user.
|
|
14
13
|
*/
|
|
15
|
-
export declare function extractDeterministicTeaching(
|
|
14
|
+
export declare function extractDeterministicTeaching(_message: string, _context?: RequestContext, _sourceEventId?: string): ExtractedTeaching;
|
package/dist/teaching.js
CHANGED
|
@@ -1,321 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.extractDeterministicTeaching = extractDeterministicTeaching;
|
|
4
|
-
function cleanValue(value, limit = 160) {
|
|
5
|
-
return value.replace(/\s+/g, ' ').replace(/^[ .,!?:;"']+|[ .,!?:;"']+$/g, '').slice(0, limit);
|
|
6
|
-
}
|
|
7
4
|
/**
|
|
8
|
-
*
|
|
5
|
+
* Deterministic teaching extraction placeholder.
|
|
9
6
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* - Companion identity is isolated.
|
|
7
|
+
* In Siduri-X, conversational memory and behavioral proposals are generated
|
|
8
|
+
* directly by the Brain LLM via structured cognitive planning (e.g. `submitResponsePlan`).
|
|
9
|
+
* Deterministic regex matching has been removed in favor of pure LLM comprehension,
|
|
10
|
+
* as all candidates are quarantined in 'pending' status until explicitly approved by the user.
|
|
15
11
|
*/
|
|
16
|
-
function extractDeterministicTeaching(
|
|
17
|
-
|
|
18
|
-
const claims = [];
|
|
19
|
-
const behaviorProposals = [];
|
|
20
|
-
if (!text) {
|
|
21
|
-
return { claims, behaviorProposals };
|
|
22
|
-
}
|
|
23
|
-
const rawActorId = context?.actor?.actorId;
|
|
24
|
-
const cleanActorId = rawActorId ? rawActorId.replace(/^actor:/, '') : undefined;
|
|
25
|
-
const actorSubject = cleanActorId ? `actor:${cleanActorId}` : 'actor:anonymous';
|
|
26
|
-
const companionId = context?.companionId || 'default';
|
|
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;
|
|
35
|
-
// 1. Companion's Name: "your name is X" / "you are called X"
|
|
36
|
-
const companionNameMatch = cleanText.match(/\b(?:your name is|you are called)\s+(.+?)(?=\s+and\s+(?:i\b|my\b|you\b)|[.;,]|$)/i);
|
|
37
|
-
if (companionNameMatch) {
|
|
38
|
-
const name = cleanValue(companionNameMatch[1], 80);
|
|
39
|
-
claims.push({
|
|
40
|
-
subject: `companion:${companionId}`,
|
|
41
|
-
predicate: 'name',
|
|
42
|
-
value: name,
|
|
43
|
-
content: `The companion's name is ${name}.`,
|
|
44
|
-
claimType: 'semantic',
|
|
45
|
-
provenance: 'deterministic_teaching',
|
|
46
|
-
sensitivity: 'public',
|
|
47
|
-
sourceEventId,
|
|
48
|
-
});
|
|
49
|
-
behaviorProposals.push({
|
|
50
|
-
directive: `Acknowledge configured name as ${name}`,
|
|
51
|
-
priority: 70,
|
|
52
|
-
subject: `companion:${companionId}`,
|
|
53
|
-
predicate: 'name',
|
|
54
|
-
value: name,
|
|
55
|
-
memoryClass: 'identity',
|
|
56
|
-
category: 'relational',
|
|
57
|
-
sourceEventId,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
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)) {
|
|
174
|
-
const name = cleanValue(myNameMatch[1], 80);
|
|
175
|
-
claims.push({
|
|
176
|
-
subject: actorSubject,
|
|
177
|
-
predicate: 'name',
|
|
178
|
-
value: name,
|
|
179
|
-
content: `The actor's name is ${name}.`,
|
|
180
|
-
claimType: 'preference',
|
|
181
|
-
provenance: 'deterministic_teaching',
|
|
182
|
-
sensitivity,
|
|
183
|
-
sourceEventId,
|
|
184
|
-
});
|
|
185
|
-
}
|
|
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);
|
|
188
|
-
if (callMeMatch) {
|
|
189
|
-
const address = cleanValue(callMeMatch[1], 80);
|
|
190
|
-
const directiveInstruction = `Address ${actorSubject} as ${address}`;
|
|
191
|
-
claims.push({
|
|
192
|
-
subject: actorSubject,
|
|
193
|
-
predicate: 'preferred_address',
|
|
194
|
-
value: address,
|
|
195
|
-
content: `The actor's preferred address is ${address}.`,
|
|
196
|
-
claimType: 'relationship',
|
|
197
|
-
provenance: 'deterministic_teaching',
|
|
198
|
-
sensitivity,
|
|
199
|
-
sourceEventId,
|
|
200
|
-
});
|
|
201
|
-
behaviorProposals.push({
|
|
202
|
-
directive: directiveInstruction,
|
|
203
|
-
priority: 80,
|
|
204
|
-
subject: actorSubject,
|
|
205
|
-
predicate: 'preferred_address',
|
|
206
|
-
value: address,
|
|
207
|
-
memoryClass: 'behavioral',
|
|
208
|
-
category: 'behavioral',
|
|
209
|
-
sourceEventId,
|
|
210
|
-
});
|
|
211
|
-
}
|
|
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);
|
|
214
|
-
if (relMatch) {
|
|
215
|
-
const relationship = cleanValue(relMatch[1], 60);
|
|
216
|
-
const actorName = relMatch[2] ? cleanValue(relMatch[2], 80) : undefined;
|
|
217
|
-
claims.push({
|
|
218
|
-
subject: actorSubject,
|
|
219
|
-
predicate: 'stated_relationship',
|
|
220
|
-
value: relationship,
|
|
221
|
-
content: `The actor stated their relationship as ${relationship}.`,
|
|
222
|
-
claimType: 'relationship',
|
|
223
|
-
provenance: 'deterministic_teaching',
|
|
224
|
-
sensitivity: 'private',
|
|
225
|
-
sourceEventId,
|
|
226
|
-
});
|
|
227
|
-
behaviorProposals.push({
|
|
228
|
-
directive: `Recognize ${actorSubject} stated relationship as ${relationship}`,
|
|
229
|
-
priority: 75,
|
|
230
|
-
subject: actorSubject,
|
|
231
|
-
predicate: 'stated_relationship',
|
|
232
|
-
value: relationship,
|
|
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,
|
|
301
|
-
sourceEventId,
|
|
302
|
-
});
|
|
303
|
-
}
|
|
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);
|
|
306
|
-
if (prefMatch) {
|
|
307
|
-
const predicate = cleanValue(prefMatch[1], 40);
|
|
308
|
-
const val = cleanValue(prefMatch[2], 100);
|
|
309
|
-
claims.push({
|
|
310
|
-
subject: actorSubject,
|
|
311
|
-
predicate: `preferred_${predicate}`,
|
|
312
|
-
value: val,
|
|
313
|
-
content: `The actor's preferred ${predicate} is ${val}.`,
|
|
314
|
-
claimType: 'preference',
|
|
315
|
-
provenance: 'deterministic_teaching',
|
|
316
|
-
sensitivity,
|
|
317
|
-
sourceEventId,
|
|
318
|
-
});
|
|
319
|
-
}
|
|
320
|
-
return { claims, behaviorProposals };
|
|
12
|
+
function extractDeterministicTeaching(_message, _context, _sourceEventId) {
|
|
13
|
+
return { claims: [], behaviorProposals: [] };
|
|
321
14
|
}
|
package/package.json
CHANGED