@sidurijs/core 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/dist/action-executor.d.ts +12 -0
  2. package/dist/action-executor.js +54 -0
  3. package/dist/action-policy.d.ts +79 -0
  4. package/dist/action-policy.js +439 -0
  5. package/dist/action-policy.test.d.ts +1 -0
  6. package/dist/action-policy.test.js +363 -0
  7. package/dist/action.d.ts +72 -0
  8. package/dist/action.js +2 -0
  9. package/dist/adversarial.test.d.ts +1 -0
  10. package/dist/adversarial.test.js +491 -0
  11. package/dist/architecture-boundary.test.d.ts +1 -0
  12. package/dist/architecture-boundary.test.js +108 -0
  13. package/dist/capability.d.ts +78 -0
  14. package/dist/capability.js +168 -0
  15. package/dist/capability.test.d.ts +1 -0
  16. package/dist/capability.test.js +311 -0
  17. package/dist/chat-contract.d.ts +94 -0
  18. package/dist/chat-contract.js +104 -0
  19. package/dist/cognition-planner.d.ts +15 -0
  20. package/dist/cognition-planner.js +23 -0
  21. package/dist/container.d.ts +74 -0
  22. package/dist/container.js +81 -0
  23. package/dist/context-retriever.d.ts +33 -0
  24. package/dist/context-retriever.js +260 -0
  25. package/dist/context.d.ts +46 -0
  26. package/dist/context.js +85 -0
  27. package/dist/context.test.d.ts +1 -0
  28. package/dist/context.test.js +76 -0
  29. package/dist/conversational-teach.test.d.ts +1 -0
  30. package/dist/conversational-teach.test.js +941 -0
  31. package/dist/database.d.ts +1 -0
  32. package/dist/database.js +17 -0
  33. package/dist/dispatcher.d.ts +14 -0
  34. package/dist/dispatcher.js +40 -0
  35. package/dist/dispatcher.test.d.ts +1 -0
  36. package/dist/dispatcher.test.js +58 -0
  37. package/dist/ear-types.d.ts +33 -0
  38. package/dist/ear-types.js +2 -0
  39. package/dist/evidence.d.ts +76 -0
  40. package/dist/evidence.js +27 -0
  41. package/dist/evidence.test.d.ts +1 -0
  42. package/dist/evidence.test.js +75 -0
  43. package/dist/experience-emitter.d.ts +21 -0
  44. package/dist/experience-emitter.js +47 -0
  45. package/dist/experience.d.ts +55 -0
  46. package/dist/experience.js +74 -0
  47. package/dist/experience.test.d.ts +1 -0
  48. package/dist/experience.test.js +55 -0
  49. package/dist/gating.d.ts +45 -0
  50. package/dist/gating.js +185 -0
  51. package/dist/gating.test.d.ts +1 -0
  52. package/dist/gating.test.js +186 -0
  53. package/dist/index.d.ts +367 -0
  54. package/dist/index.js +56 -0
  55. package/dist/input-normalizer.d.ts +14 -0
  56. package/dist/input-normalizer.js +76 -0
  57. package/dist/input-normalizer.test.d.ts +1 -0
  58. package/dist/input-normalizer.test.js +48 -0
  59. package/dist/intent-classifier.d.ts +37 -0
  60. package/dist/intent-classifier.js +150 -0
  61. package/dist/intent-classifier.test.d.ts +1 -0
  62. package/dist/intent-classifier.test.js +118 -0
  63. package/dist/memory-settler.d.ts +49 -0
  64. package/dist/memory-settler.js +161 -0
  65. package/dist/mouth-types.d.ts +90 -0
  66. package/dist/mouth-types.js +2 -0
  67. package/dist/perception-cycle.test.d.ts +1 -0
  68. package/dist/perception-cycle.test.js +301 -0
  69. package/dist/perception-pipeline.d.ts +77 -0
  70. package/dist/perception-pipeline.js +304 -0
  71. package/dist/perception-pipeline.test.d.ts +1 -0
  72. package/dist/perception-pipeline.test.js +65 -0
  73. package/dist/prompt-compiler.d.ts +26 -0
  74. package/dist/prompt-compiler.js +81 -0
  75. package/dist/prompt-compiler.test.d.ts +1 -0
  76. package/dist/prompt-compiler.test.js +90 -0
  77. package/dist/proposals.d.ts +33 -0
  78. package/dist/proposals.js +2 -0
  79. package/dist/response-envelope.d.ts +30 -0
  80. package/dist/response-envelope.js +90 -0
  81. package/dist/runtime-facades.test.d.ts +1 -0
  82. package/dist/runtime-facades.test.js +95 -0
  83. package/dist/runtime.d.ts +116 -0
  84. package/dist/runtime.js +778 -0
  85. package/dist/schema-validator.d.ts +9 -0
  86. package/dist/schema-validator.js +107 -0
  87. package/dist/schema-validator.test.d.ts +1 -0
  88. package/dist/schema-validator.test.js +124 -0
  89. package/dist/session-history.d.ts +20 -0
  90. package/dist/session-history.js +55 -0
  91. package/dist/session-history.test.d.ts +1 -0
  92. package/dist/session-history.test.js +38 -0
  93. package/dist/siduri-db.d.ts +235 -0
  94. package/dist/siduri-db.js +1405 -0
  95. package/dist/siduri-db.test.d.ts +1 -0
  96. package/dist/siduri-db.test.js +1021 -0
  97. package/dist/sqlite-action-store.d.ts +21 -0
  98. package/dist/sqlite-action-store.js +281 -0
  99. package/dist/sqlite-action-store.test.d.ts +1 -0
  100. package/dist/sqlite-action-store.test.js +261 -0
  101. package/dist/teaching.d.ts +14 -0
  102. package/dist/teaching.js +14 -0
  103. package/package.json +43 -0
@@ -0,0 +1,778 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SiduriRuntime = void 0;
4
+ exports.promoteApprovedClaimToSelf = promoteApprovedClaimToSelf;
5
+ exports.isSelfAffectingClaim = isSelfAffectingClaim;
6
+ exports.isKnowledgeAffectingClaim = isKnowledgeAffectingClaim;
7
+ exports.promoteApprovedClaimToKnowledge = promoteApprovedClaimToKnowledge;
8
+ const perception_pipeline_1 = require("./perception-pipeline");
9
+ const container_1 = require("./container");
10
+ /**
11
+ * SiduriRuntime coordinates companion perception and cognition execution.
12
+ * Lifecycle management and organ storage are handled by CompanionContainer.
13
+ * The 12-stage perception cycle is executed via PerceptionPipeline.
14
+ */
15
+ class SiduriRuntime {
16
+ id;
17
+ config;
18
+ container;
19
+ pipeline;
20
+ constructor(id, config, containerOrOrgans = {}, pipeline) {
21
+ this.id = id;
22
+ this.config = config;
23
+ if (containerOrOrgans instanceof container_1.CompanionContainer) {
24
+ this.container = containerOrOrgans;
25
+ }
26
+ else {
27
+ this.container = new container_1.CompanionContainer(id, config, containerOrOrgans);
28
+ }
29
+ this.pipeline = pipeline || (0, perception_pipeline_1.createDefaultPerceptionPipeline)();
30
+ }
31
+ // Direct organ accessors through container
32
+ get organs() { return this.container.organs; }
33
+ get brain() { return this.container.brain; }
34
+ get memory() { return this.container.memory; }
35
+ get voice() { return this.container.voice; }
36
+ get knowledge() { return this.container.knowledge; }
37
+ get vision() { return this.container.vision; }
38
+ get behavior() { return this.container.behavior; }
39
+ get body() { return this.container.body; }
40
+ get hands() { return this.container.hands; }
41
+ get ear() { return this.container.ear; }
42
+ get observation() { return this.container.observation; }
43
+ set observation(org) { this.container.observation = org; }
44
+ get mouth() { return this.container.mouth; }
45
+ get self() { return this.container.self; }
46
+ get externalKnowledge() { return this.container.externalKnowledge; }
47
+ get gating() { return this.container.gating; }
48
+ get actionPolicy() { return this.container.actionPolicy; }
49
+ get dispatcher() { return this.container.dispatcher; }
50
+ get sessionHistory() { return this.container.sessionHistory; }
51
+ // Conversation history accessors
52
+ get conversationHistory() {
53
+ return this.container.sessionHistory.getHistory('default');
54
+ }
55
+ set conversationHistory(messages) {
56
+ this.container.sessionHistory.setHistory('default', messages);
57
+ }
58
+ async initialize() {
59
+ await this.container.initialize();
60
+ if (this.memory && this.self && typeof this.memory.approveClaim === 'function') {
61
+ const originalApproveClaim = this.memory.approveClaim.bind(this.memory);
62
+ this.memory.approveClaim = async (id) => {
63
+ await originalApproveClaim(id);
64
+ const targetCompId = this.id;
65
+ const claims = typeof this.memory.getAllClaims === 'function'
66
+ ? await this.memory.getAllClaims(500)
67
+ : await this.memory.getClaims(500);
68
+ let found = claims.find((c) => c.id === id);
69
+ if (!found && typeof this.memory.getPendingClaims === 'function') {
70
+ const pending = await this.memory.getPendingClaims(500);
71
+ found = pending.find((c) => c.id === id);
72
+ }
73
+ if (found && this.self) {
74
+ await promoteApprovedClaimToSelf(found, this.self, targetCompId);
75
+ }
76
+ if (found && this.container.knowledge) {
77
+ await promoteApprovedClaimToKnowledge(found, this.container.knowledge, targetCompId);
78
+ }
79
+ };
80
+ }
81
+ // Sync any pre-existing approved claims to Knowledge / Life DB
82
+ if (this.memory && this.container.knowledge) {
83
+ try {
84
+ const claims = typeof this.memory.getAllClaims === 'function'
85
+ ? await this.memory.getAllClaims(500)
86
+ : await this.memory.getClaims(500);
87
+ const approvedClaims = (claims || []).filter((c) => (c.status || '').toLowerCase() === 'approved');
88
+ for (const c of approvedClaims) {
89
+ await promoteApprovedClaimToKnowledge(c, this.container.knowledge, this.id);
90
+ }
91
+ }
92
+ catch {
93
+ // non-blocking
94
+ }
95
+ }
96
+ }
97
+ get db() {
98
+ return this.container.db || this.memory?.db || this.self?.db;
99
+ }
100
+ log(level, subsystem, message, metadata) {
101
+ if (this.db && typeof this.db.insertLog === 'function') {
102
+ return this.db.insertLog({
103
+ companionId: this.id,
104
+ level,
105
+ subsystem,
106
+ message,
107
+ metadata,
108
+ });
109
+ }
110
+ }
111
+ queryLogs(options) {
112
+ if (this.db && typeof this.db.queryLogs === 'function') {
113
+ return this.db.queryLogs({
114
+ companionId: options?.companionId || this.id,
115
+ ...options,
116
+ });
117
+ }
118
+ return [];
119
+ }
120
+ clearLogs(companionId) {
121
+ if (this.db && typeof this.db.clearLogs === 'function') {
122
+ this.db.clearLogs(companionId || this.id);
123
+ }
124
+ }
125
+ getSessionHistory(sessionKey) {
126
+ return this.container.sessionHistory.getHistory(sessionKey);
127
+ }
128
+ clearHistory(sessionKey) {
129
+ this.container.sessionHistory.clear(sessionKey);
130
+ }
131
+ /**
132
+ * Approves a memory proposal or behavior proposal and canonically promotes
133
+ * Self-affecting mutations to SelfRepository.
134
+ */
135
+ async approveProposal(proposalId, options) {
136
+ const companionId = options?.companionId || this.id;
137
+ // 1. Approve claim in memory if present
138
+ if (this.memory && typeof this.memory.approveClaim === 'function') {
139
+ await this.memory.approveClaim(proposalId);
140
+ }
141
+ // 2. Fetch claim
142
+ let claim;
143
+ if (this.memory) {
144
+ const claims = typeof this.memory.getAllClaims === 'function'
145
+ ? await this.memory.getAllClaims(500)
146
+ : await this.memory.getClaims(500);
147
+ claim = claims.find((c) => c.id === proposalId);
148
+ if (!claim && typeof this.memory.getPendingClaims === 'function') {
149
+ const pending = await this.memory.getPendingClaims(500);
150
+ claim = pending.find((c) => c.id === proposalId);
151
+ }
152
+ }
153
+ // 3. Promote to Knowledge / Life DB if claim is Knowledge-affecting
154
+ if (claim && this.container.knowledge) {
155
+ const promotedToKnowledge = await promoteApprovedClaimToKnowledge(claim, this.container.knowledge, companionId);
156
+ if (promotedToKnowledge) {
157
+ this.log('info', 'truth_gate', `Approved and promoted claim '${proposalId}' to Knowledge / Life DB`, {
158
+ proposalId,
159
+ companionId,
160
+ target: 'knowledge',
161
+ subject: claim.subject,
162
+ predicate: claim.predicate,
163
+ });
164
+ return { success: true, target: 'knowledge' };
165
+ }
166
+ }
167
+ // 4. Promote to SelfRepository if claim is Self-affecting
168
+ if (claim && this.self) {
169
+ await promoteApprovedClaimToSelf(claim, this.self, companionId);
170
+ const identity = typeof this.self.getIdentity === 'function' ? await this.self.getIdentity(companionId) : null;
171
+ this.log('info', 'truth_gate', `Approved and promoted claim '${proposalId}' to Self`, {
172
+ proposalId,
173
+ companionId,
174
+ target: 'self',
175
+ subject: claim.subject,
176
+ predicate: claim.predicate,
177
+ });
178
+ return { success: true, target: 'self', name: identity?.name };
179
+ }
180
+ // 5. Also check if this proposal ID is a behavioral directive in Self
181
+ if (this.self && typeof this.self.approveDirective === 'function') {
182
+ try {
183
+ await this.self.approveDirective(proposalId, companionId);
184
+ const identity = typeof this.self.getIdentity === 'function' ? await this.self.getIdentity(companionId) : null;
185
+ this.log('info', 'truth_gate', `Approved behavioral directive proposal '${proposalId}'`, {
186
+ proposalId,
187
+ companionId,
188
+ target: 'self',
189
+ });
190
+ return { success: true, target: 'self', name: identity?.name };
191
+ }
192
+ catch {
193
+ // Not a pending directive or already active
194
+ }
195
+ }
196
+ const identity = this.self && typeof this.self.getIdentity === 'function' ? await this.self.getIdentity(companionId) : null;
197
+ this.log('info', 'truth_gate', `Approved memory proposal '${proposalId}'`, {
198
+ proposalId,
199
+ companionId,
200
+ target: 'memory',
201
+ });
202
+ return { success: true, target: 'memory', name: identity?.name };
203
+ }
204
+ /**
205
+ * Rejects a memory or behavior proposal.
206
+ */
207
+ async rejectProposal(proposalId, options) {
208
+ const companionId = options?.companionId || this.id;
209
+ if (this.memory && typeof this.memory.rejectClaim === 'function') {
210
+ await this.memory.rejectClaim(proposalId);
211
+ }
212
+ if (this.self && typeof this.self.rejectDirective === 'function') {
213
+ try {
214
+ await this.self.rejectDirective(proposalId, companionId);
215
+ }
216
+ catch {
217
+ // ignore
218
+ }
219
+ }
220
+ this.log('info', 'truth_gate', `Rejected proposal '${proposalId}'`, {
221
+ proposalId,
222
+ companionId,
223
+ });
224
+ return { success: true };
225
+ }
226
+ /**
227
+ * Approves a behavioral directive in Self and Memory.
228
+ */
229
+ async approveDirective(directiveId, options) {
230
+ const companionId = options?.companionId || this.id;
231
+ if (this.self && typeof this.self.approveDirective === 'function') {
232
+ await this.self.approveDirective(directiveId, companionId);
233
+ }
234
+ if (this.memory && typeof this.memory.approveDirective === 'function') {
235
+ await this.memory.approveDirective(directiveId, companionId);
236
+ }
237
+ // If directive pertains to companion name, ensure self identity reflects it
238
+ if (this.self && typeof this.self.getActiveDirectives === 'function') {
239
+ try {
240
+ const activeDirs = await this.self.getActiveDirectives(companionId);
241
+ const dir = activeDirs.find((d) => d.id === directiveId);
242
+ if (dir?.directive) {
243
+ const compNameMatch = dir.directive.match(/^(?:address\s+companion\s+as|your\s+name\s+is|call\s+yourself|acknowledge\s+name\s+as|companion\s+name\s+is)\s+["“']?([^"”'.]+)["”']?/i);
244
+ if (compNameMatch) {
245
+ const newName = compNameMatch[1].trim();
246
+ if (newName) {
247
+ const currentIdentity = (await this.self.getIdentity(companionId)) || {
248
+ companionId,
249
+ name: '',
250
+ version: '1.0.0',
251
+ updatedAt: new Date().toISOString(),
252
+ };
253
+ currentIdentity.name = newName;
254
+ currentIdentity.updatedAt = new Date().toISOString();
255
+ await this.self.setIdentity(currentIdentity);
256
+ }
257
+ }
258
+ }
259
+ }
260
+ catch {
261
+ // non-blocking
262
+ }
263
+ }
264
+ const identity = this.self && typeof this.self.getIdentity === 'function' ? await this.self.getIdentity(companionId) : null;
265
+ this.log('info', 'truth_gate', `Approved behavioral directive '${directiveId}'`, {
266
+ directiveId,
267
+ companionId,
268
+ });
269
+ return { success: true, name: identity?.name };
270
+ }
271
+ /**
272
+ * Rejects a behavioral directive in Self and Memory.
273
+ */
274
+ async rejectDirective(directiveId, options) {
275
+ const companionId = options?.companionId || this.id;
276
+ if (this.self && typeof this.self.rejectDirective === 'function') {
277
+ await this.self.rejectDirective(directiveId, companionId);
278
+ }
279
+ if (this.memory && typeof this.memory.rejectDirective === 'function') {
280
+ await this.memory.rejectDirective(directiveId, companionId);
281
+ }
282
+ this.log('info', 'truth_gate', `Rejected behavioral directive '${directiveId}'`, {
283
+ directiveId,
284
+ companionId,
285
+ });
286
+ return { success: true };
287
+ }
288
+ /**
289
+ * Revokes a behavioral directive in Self and Memory.
290
+ */
291
+ async revokeDirective(directiveId, options) {
292
+ const companionId = options?.companionId || this.id;
293
+ if (this.self && typeof this.self.revokeDirective === 'function') {
294
+ await this.self.revokeDirective(directiveId, companionId);
295
+ }
296
+ if (this.memory && typeof this.memory.revokeDirective === 'function') {
297
+ await this.memory.revokeDirective(directiveId, companionId);
298
+ }
299
+ return { success: true };
300
+ }
301
+ /**
302
+ * Processes an incoming perception (sensory audio, text, platform event, or observation alert)
303
+ * through the decoupled PerceptionPipeline.
304
+ */
305
+ async processPerception(perception) {
306
+ const context = {
307
+ companionId: this.id,
308
+ companionName: this.config.name,
309
+ perception,
310
+ organs: this.container.organs,
311
+ gating: this.container.gating,
312
+ actionPolicy: this.container.actionPolicy,
313
+ dispatcher: this.container.dispatcher,
314
+ sessionHistory: this.container.sessionHistory,
315
+ rawText: perception.text || '',
316
+ };
317
+ return this.pipeline.execute(context);
318
+ }
319
+ /**
320
+ * Primary entrypoint for text chat messages.
321
+ */
322
+ async handleUserMessage(message, roleOrContext = 'OWNER', history = [], medium, signal, subtitleLanguage) {
323
+ return this.processPerception({
324
+ source: 'text_chat',
325
+ text: message,
326
+ roleOrContext,
327
+ history,
328
+ medium,
329
+ signal,
330
+ subtitleLanguage,
331
+ });
332
+ }
333
+ }
334
+ exports.SiduriRuntime = SiduriRuntime;
335
+ /**
336
+ * Canonically promotes an approved Claim into SelfRepository state.
337
+ */
338
+ async function promoteApprovedClaimToSelf(claim, self, companionId) {
339
+ const targetCompanionId = companionId || claim.companionId || 'default';
340
+ const subject = (claim.subject || '').toLowerCase();
341
+ const predicate = (claim.predicate || '').toLowerCase();
342
+ const value = claim.value || '';
343
+ if (!value)
344
+ return;
345
+ // 1. Identity mutations: companion identity/role/origin/name/ethos
346
+ const isCompanionTarget = subject.startsWith('companion') ||
347
+ subject === 'siduri' ||
348
+ subject === 'self' ||
349
+ subject === 'assistant' ||
350
+ subject === 'persona' ||
351
+ subject === 'ai' ||
352
+ subject === 'me' ||
353
+ ((predicate === 'name' || predicate === 'role' || predicate === 'archetype' || predicate === 'ethos' || predicate === 'origin') &&
354
+ !subject.startsWith('actor:') &&
355
+ subject !== 'user' &&
356
+ subject !== 'primary_user' &&
357
+ subject !== 'owner' &&
358
+ subject !== 'creator');
359
+ if (isCompanionTarget) {
360
+ const existing = (await self.getIdentity(targetCompanionId)) || {
361
+ companionId: targetCompanionId,
362
+ name: '',
363
+ version: '1.0.0',
364
+ updatedAt: new Date().toISOString(),
365
+ };
366
+ if (predicate === 'role' || predicate === 'archetype') {
367
+ existing.archetype = value;
368
+ existing.role = value;
369
+ existing.updatedAt = new Date().toISOString();
370
+ await self.setIdentity(existing);
371
+ await self.commitDirectives(targetCompanionId, [
372
+ {
373
+ id: `dir-role-${claim.id || Date.now()}`,
374
+ companionId: targetCompanionId,
375
+ priority: 70,
376
+ directive: `Acknowledge role as ${value}`,
377
+ status: 'active',
378
+ category: 'relational',
379
+ createdAt: new Date().toISOString(),
380
+ },
381
+ ]);
382
+ }
383
+ else if (predicate === 'origin' || predicate === 'created_by') {
384
+ existing.origin = value;
385
+ existing.updatedAt = new Date().toISOString();
386
+ await self.setIdentity(existing);
387
+ }
388
+ else if (predicate === 'name') {
389
+ existing.name = value;
390
+ existing.updatedAt = new Date().toISOString();
391
+ await self.setIdentity(existing);
392
+ }
393
+ else if (predicate === 'ethos') {
394
+ existing.ethos = value;
395
+ existing.updatedAt = new Date().toISOString();
396
+ await self.setIdentity(existing);
397
+ }
398
+ return;
399
+ }
400
+ // 2. Relationship mutations: creator or user stated relationship, name, or affiliation
401
+ if (claim.claimType === 'relationship' ||
402
+ predicate === 'stated_relationship' ||
403
+ predicate === 'relationship' ||
404
+ predicate === 'relationship_to_companion' ||
405
+ predicate === 'relationship_to_siduri' ||
406
+ (predicate === 'name' && (subject.startsWith('actor:') || subject === 'user' || subject === 'primary_user')) ||
407
+ predicate === 'preferred_address' ||
408
+ predicate === 'affiliation') {
409
+ const rawSubject = (claim.subject || 'actor:user').replace(/^actor:actor:/, 'actor:');
410
+ const isCreator = value.toLowerCase().includes('creator');
411
+ const isName = predicate === 'name' || predicate === 'preferred_address';
412
+ const isAffil = predicate === 'affiliation';
413
+ const existingRel = typeof self.getRelationship === 'function'
414
+ ? await self.getRelationship(targetCompanionId, rawSubject)
415
+ : null;
416
+ const isPriorCreator = existingRel?.role === 'creator' || (existingRel?.stance === 'familiar_loyal' && existingRel.trustScore === 1.0);
417
+ const role = isCreator
418
+ ? 'creator'
419
+ : (isPriorCreator ? 'creator' : (existingRel?.role && existingRel.role !== 'user' ? existingRel.role : (isName || isAffil ? existingRel?.role || 'user' : value)));
420
+ const name = isName ? value : existingRel?.name;
421
+ const affiliation = isAffil ? value : existingRel?.affiliation;
422
+ const stance = isCreator || isPriorCreator ? 'familiar_loyal' : (existingRel?.stance || 'neutral');
423
+ const trustScore = isCreator || isPriorCreator ? 1.0 : (existingRel?.trustScore ?? 0.8);
424
+ const familiarity = isCreator || isPriorCreator ? 0.9 : (existingRel?.familiarity ?? 0.5);
425
+ const interactionConventions = isCreator || isPriorCreator
426
+ ? Array.from(new Set([...(existingRel?.interactionConventions || []), 'Direct communication', 'Highest administrative trust']))
427
+ : (existingRel?.interactionConventions || []);
428
+ await self.updateRelationship(targetCompanionId, {
429
+ companionId: targetCompanionId,
430
+ entityId: rawSubject,
431
+ entityType: 'human',
432
+ name,
433
+ affiliation,
434
+ role,
435
+ stance,
436
+ trustScore,
437
+ familiarity,
438
+ interactionConventions,
439
+ });
440
+ // Dual promotion: If this actor is established as creator, also populate companion's origin in self_identity
441
+ if (isCreator || (isName && isPriorCreator)) {
442
+ const existingIdentity = (await self.getIdentity(targetCompanionId)) || {
443
+ companionId: targetCompanionId,
444
+ name: 'Siduri',
445
+ version: '1.0.0',
446
+ updatedAt: new Date().toISOString(),
447
+ };
448
+ const creatorName = name || existingRel?.name || (rawSubject.startsWith('actor:') && rawSubject !== 'actor:user' && rawSubject !== 'actor:primary' ? rawSubject.slice(6) : value);
449
+ existingIdentity.origin = creatorName !== 'user' && creatorName !== 'primary' ? creatorName : value;
450
+ existingIdentity.updatedAt = new Date().toISOString();
451
+ await self.setIdentity(existingIdentity);
452
+ }
453
+ if (isName) {
454
+ await self.commitDirectives(targetCompanionId, [
455
+ {
456
+ id: `dir-name-${claim.id || Date.now()}`,
457
+ companionId: targetCompanionId,
458
+ priority: 75,
459
+ directive: `Address ${rawSubject} as ${value}`,
460
+ status: 'active',
461
+ category: 'relational',
462
+ createdAt: new Date().toISOString(),
463
+ },
464
+ ]);
465
+ }
466
+ return;
467
+ }
468
+ // 3. Behavioral rule claim
469
+ if (predicate === 'behavioral_rule' || predicate === 'rule') {
470
+ await self.commitDirectives(targetCompanionId, [
471
+ {
472
+ id: `dir-rule-${claim.id || Date.now()}`,
473
+ companionId: targetCompanionId,
474
+ priority: 60,
475
+ directive: value,
476
+ status: 'active',
477
+ category: 'behavioral',
478
+ createdAt: new Date().toISOString(),
479
+ },
480
+ ]);
481
+ }
482
+ }
483
+ function isSelfAffectingClaim(claim) {
484
+ if (!claim)
485
+ return false;
486
+ const subject = (claim.subject || '').toLowerCase();
487
+ const predicate = (claim.predicate || '').toLowerCase();
488
+ return (subject.startsWith('companion') ||
489
+ subject === 'siduri' ||
490
+ subject === 'self' ||
491
+ subject === 'assistant' ||
492
+ subject === 'persona' ||
493
+ subject === 'ai' ||
494
+ subject === 'me' ||
495
+ claim.claimType === 'relationship' ||
496
+ predicate === 'stated_relationship' ||
497
+ predicate === 'relationship' ||
498
+ predicate === 'relationship_to_companion' ||
499
+ predicate === 'relationship_to_siduri' ||
500
+ predicate === 'name' ||
501
+ predicate === 'preferred_address' ||
502
+ predicate === 'affiliation' ||
503
+ predicate === 'role' ||
504
+ predicate === 'archetype' ||
505
+ predicate === 'origin' ||
506
+ predicate === 'created_by' ||
507
+ predicate === 'ethos' ||
508
+ predicate === 'behavioral_rule' ||
509
+ predicate === 'rule');
510
+ }
511
+ function isKnowledgeAffectingClaim(claim) {
512
+ if (!claim)
513
+ return false;
514
+ const subject = (claim.subject || '').toLowerCase();
515
+ const predicate = (claim.predicate || '').toLowerCase();
516
+ const claimType = (claim.claimType || '').toLowerCase();
517
+ return (claim.target === 'knowledge' ||
518
+ claimType === 'life_entity' ||
519
+ claimType === 'entity' ||
520
+ claimType === 'inventory' ||
521
+ claimType === 'life_event' ||
522
+ claimType === 'event' ||
523
+ claimType === 'finance' ||
524
+ claimType === 'life_task' ||
525
+ claimType === 'task' ||
526
+ claimType === 'life_schedule' ||
527
+ claimType === 'schedule' ||
528
+ claimType === 'preference' ||
529
+ claimType === 'life_preference' ||
530
+ subject.startsWith('inventory:') ||
531
+ subject.startsWith('finance:') ||
532
+ subject.startsWith('task:') ||
533
+ subject.startsWith('todo:') ||
534
+ subject.startsWith('schedule:') ||
535
+ subject.startsWith('preference:') ||
536
+ subject.startsWith('entity:') ||
537
+ subject.startsWith('event:') ||
538
+ predicate === 'owns' ||
539
+ predicate === 'inventory' ||
540
+ predicate === 'expense' ||
541
+ predicate === 'income' ||
542
+ predicate === 'spent' ||
543
+ predicate === 'task' ||
544
+ predicate === 'todo' ||
545
+ predicate === 'goal' ||
546
+ predicate === 'schedule' ||
547
+ predicate === 'appointment' ||
548
+ predicate === 'meeting' ||
549
+ predicate === 'preference' ||
550
+ predicate === 'favorite' ||
551
+ predicate === 'prefers');
552
+ }
553
+ /**
554
+ * Canonically promotes an approved Claim into Knowledge / LifeDatabase state.
555
+ */
556
+ async function promoteApprovedClaimToKnowledge(claim, knowledge, companionId) {
557
+ if (!knowledge)
558
+ return false;
559
+ const targetCompanionId = companionId || claim.companionId || 'default';
560
+ const subject = (claim.subject || '').toLowerCase();
561
+ const predicate = (claim.predicate || '').toLowerCase();
562
+ const claimType = (claim.claimType || '').toLowerCase();
563
+ const value = claim.value || '';
564
+ const evidenceObj = typeof claim.evidence === 'object' && claim.evidence ? claim.evidence : {};
565
+ // 1. Entities / Inventory
566
+ const isEntityClaim = claimType === 'life_entity' ||
567
+ claimType === 'entity' ||
568
+ claimType === 'inventory' ||
569
+ subject.startsWith('inventory:') ||
570
+ subject.startsWith('entity:') ||
571
+ predicate === 'owns' ||
572
+ predicate.startsWith('owns_') ||
573
+ predicate.startsWith('owns ') ||
574
+ predicate === 'inventory' ||
575
+ predicate.includes('character') ||
576
+ predicate.includes('account') ||
577
+ predicate.includes('device') ||
578
+ predicate.includes('hardware') ||
579
+ predicate.includes('weapon') ||
580
+ predicate.includes('item');
581
+ if (isEntityClaim) {
582
+ const rawName = subject.startsWith('inventory:')
583
+ ? claim.subject.slice(10)
584
+ : (subject.startsWith('entity:')
585
+ ? claim.subject.slice(7)
586
+ : ((predicate === 'owns' || predicate.startsWith('owns') || predicate.includes('character') || predicate.includes('account') || predicate.includes('item') || predicate.includes('weapon'))
587
+ ? value
588
+ : claim.subject));
589
+ const entityName = rawName || 'Unnamed Entity';
590
+ let inferredDomain = claim.domain || evidenceObj.domain || claim.knowledge_domain;
591
+ if (!inferredDomain) {
592
+ if (predicate.includes('game') ||
593
+ predicate.includes('character') ||
594
+ predicate.includes('weapon') ||
595
+ predicate.includes('roster')) {
596
+ inferredDomain = 'gaming';
597
+ }
598
+ else if (claimType === 'inventory' ||
599
+ subject.startsWith('inventory:') ||
600
+ predicate.includes('device') ||
601
+ predicate.includes('hardware')) {
602
+ inferredDomain = 'hardware';
603
+ }
604
+ else {
605
+ inferredDomain = 'general';
606
+ }
607
+ }
608
+ let inferredEntityType = claim.entityType || evidenceObj.entityType;
609
+ if (!inferredEntityType) {
610
+ if (predicate.includes('character')) {
611
+ inferredEntityType = 'character';
612
+ }
613
+ else if (predicate.includes('account')) {
614
+ inferredEntityType = 'game_account';
615
+ }
616
+ else if (predicate.includes('weapon')) {
617
+ inferredEntityType = 'weapon';
618
+ }
619
+ else if (claimType === 'inventory' || subject.startsWith('inventory:') || predicate.includes('device') || predicate.includes('hardware')) {
620
+ inferredEntityType = 'hardware';
621
+ }
622
+ else {
623
+ inferredEntityType = 'entity';
624
+ }
625
+ }
626
+ const properties = {
627
+ description: value,
628
+ predicate: claim.predicate,
629
+ ...(typeof claim.properties === 'object' ? claim.properties : {}),
630
+ ...(typeof evidenceObj.properties === 'object' ? evidenceObj.properties : {}),
631
+ ...(typeof claim.metadata === 'object' ? claim.metadata : {}),
632
+ };
633
+ if (knowledge.entities && typeof knowledge.entities.saveEntity === 'function') {
634
+ await knowledge.entities.saveEntity({
635
+ id: claim.id || `ent-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
636
+ companionId: targetCompanionId,
637
+ entityType: inferredEntityType,
638
+ domain: inferredDomain,
639
+ name: entityName,
640
+ properties,
641
+ updatedAt: new Date().toISOString(),
642
+ });
643
+ return true;
644
+ }
645
+ else if (knowledge.inventory && typeof knowledge.inventory.saveItem === 'function') {
646
+ await knowledge.inventory.saveItem({
647
+ id: claim.id || `inv-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
648
+ companionId: targetCompanionId,
649
+ domain: inferredDomain,
650
+ entityName,
651
+ properties,
652
+ updatedAt: new Date().toISOString(),
653
+ });
654
+ return true;
655
+ }
656
+ }
657
+ // 2. Events / Finance / Telemetry
658
+ if (claimType === 'life_event' ||
659
+ claimType === 'event' ||
660
+ claimType === 'finance' ||
661
+ subject.startsWith('finance:') ||
662
+ subject.startsWith('event:') ||
663
+ predicate === 'expense' ||
664
+ predicate === 'income' ||
665
+ predicate === 'spent') {
666
+ const stream = claim.stream || evidenceObj.stream || (claimType === 'finance' || subject.startsWith('finance:') || predicate === 'expense' || predicate === 'income' ? 'finance' : 'telemetry');
667
+ const parsedAmount = typeof claim.metricValue === 'number'
668
+ ? claim.metricValue
669
+ : (typeof evidenceObj.metricValue === 'number'
670
+ ? evidenceObj.metricValue
671
+ : (typeof claim.amount === 'number'
672
+ ? claim.amount
673
+ : (typeof evidenceObj.amount === 'number'
674
+ ? evidenceObj.amount
675
+ : parseFloat(value) || 0)));
676
+ if (knowledge.events && typeof knowledge.events.addEvent === 'function') {
677
+ await knowledge.events.addEvent({
678
+ id: claim.id || `evt-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
679
+ companionId: targetCompanionId,
680
+ stream,
681
+ timestamp: claim.timestamp || evidenceObj.timestamp || new Date().toISOString(),
682
+ metricValue: parsedAmount,
683
+ metadata: {
684
+ category: claim.category || evidenceObj.category || predicate,
685
+ value,
686
+ ...(typeof claim.metadata === 'object' ? claim.metadata : {}),
687
+ ...(typeof evidenceObj.metadata === 'object' ? evidenceObj.metadata : {}),
688
+ },
689
+ });
690
+ return true;
691
+ }
692
+ else if (knowledge.finance && typeof knowledge.finance.addEntry === 'function') {
693
+ await knowledge.finance.addEntry({
694
+ id: claim.id || `fin-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
695
+ companionId: targetCompanionId,
696
+ category: claim.category || evidenceObj.category || 'general',
697
+ amount: parsedAmount,
698
+ currency: claim.currency || evidenceObj.currency || 'USD',
699
+ timestamp: claim.timestamp || evidenceObj.timestamp || new Date().toISOString(),
700
+ metadata: typeof claim.metadata === 'object' ? claim.metadata : { detail: value },
701
+ });
702
+ return true;
703
+ }
704
+ }
705
+ // 3. Tasks / To-dos / Goals
706
+ if (claimType === 'life_task' ||
707
+ claimType === 'task' ||
708
+ subject.startsWith('task:') ||
709
+ subject.startsWith('todo:') ||
710
+ predicate === 'task' ||
711
+ predicate === 'todo' ||
712
+ predicate === 'goal' ||
713
+ predicate.startsWith('task_') ||
714
+ predicate.startsWith('todo_') ||
715
+ predicate.includes('task') ||
716
+ predicate.includes('todo')) {
717
+ const title = value || (subject.startsWith('task:') ? claim.subject.slice(5) : claim.subject);
718
+ if (knowledge.tasks && typeof knowledge.tasks.saveTask === 'function') {
719
+ await knowledge.tasks.saveTask({
720
+ id: claim.id || `tsk-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
721
+ companionId: targetCompanionId,
722
+ title,
723
+ status: claim.taskStatus || evidenceObj.status || claim.metadata?.status || (claim.status && claim.status !== 'pending' && claim.status !== 'approved' ? claim.status : 'backlog'),
724
+ priority: claim.priority || evidenceObj.priority || 0,
725
+ targetDate: claim.targetDate || evidenceObj.targetDate || claim.dueDate,
726
+ metadata: typeof claim.metadata === 'object' ? claim.metadata : (typeof evidenceObj.metadata === 'object' ? evidenceObj.metadata : undefined),
727
+ updatedAt: new Date().toISOString(),
728
+ });
729
+ return true;
730
+ }
731
+ }
732
+ // 4. Schedule / Deadlines
733
+ if (claimType === 'life_schedule' ||
734
+ claimType === 'schedule' ||
735
+ subject.startsWith('schedule:') ||
736
+ predicate === 'schedule' ||
737
+ predicate === 'appointment' ||
738
+ predicate === 'meeting' ||
739
+ predicate.includes('schedule') ||
740
+ predicate.includes('calendar')) {
741
+ const title = value || (subject.startsWith('schedule:') ? claim.subject.slice(9) : claim.subject);
742
+ if (knowledge.schedule && typeof knowledge.schedule.saveItem === 'function') {
743
+ await knowledge.schedule.saveItem({
744
+ id: claim.id || `sch-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
745
+ companionId: targetCompanionId,
746
+ title,
747
+ startTime: claim.startTime || claim.start_time || new Date().toISOString(),
748
+ endTime: claim.endTime || claim.end_time,
749
+ isRecurring: Boolean(claim.isRecurring || claim.is_recurring),
750
+ status: claim.status || 'active',
751
+ });
752
+ return true;
753
+ }
754
+ }
755
+ // 5. Preferences (e.g. food preference, theme)
756
+ if (claimType === 'preference' ||
757
+ claimType === 'life_preference' ||
758
+ subject.startsWith('preference:') ||
759
+ predicate === 'preference' ||
760
+ predicate === 'favorite' ||
761
+ predicate === 'prefers') {
762
+ const prefKey = subject.startsWith('preference:')
763
+ ? claim.subject.slice(11)
764
+ : (predicate === 'favorite' || predicate === 'prefers' ? claim.subject : (claim.key || claim.preferenceKey || 'user_preference'));
765
+ if (knowledge.preferences && typeof knowledge.preferences.setPreference === 'function') {
766
+ await knowledge.preferences.setPreference({
767
+ id: claim.id || `pref-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
768
+ companionId: targetCompanionId,
769
+ preferenceKey: prefKey,
770
+ preferenceValue: value,
771
+ category: claim.category || 'general',
772
+ updatedAt: new Date().toISOString(),
773
+ });
774
+ return true;
775
+ }
776
+ }
777
+ return false;
778
+ }