blun-king-cli 9.1.386 → 9.1.387
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.
|
@@ -20,7 +20,7 @@ function safeId(value) {
|
|
|
20
20
|
return SAFE_ID_RE.test(text) ? text : '';
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
function authorizeAttentionCandidate({ store, tenantId, currentAgent, now, input } = {}) {
|
|
23
|
+
function authorizeAttentionCandidate({ store, tenantId, currentAgent, now, input, memoryAccess } = {}) {
|
|
24
24
|
if (!store || typeof store.authorizeAttention !== 'function' || typeof now !== 'function'
|
|
25
25
|
|| !exactKeys(input, new Set(['candidate', 'channel', 'authorization']))) fail();
|
|
26
26
|
const tenant = safeId(tenantId);
|
|
@@ -61,7 +61,7 @@ function authorizeAttentionCandidate({ store, tenantId, currentAgent, now, input
|
|
|
61
61
|
receiptId,
|
|
62
62
|
authority,
|
|
63
63
|
authorizedAt: new Date(issuedAtMs).toISOString(),
|
|
64
|
-
});
|
|
64
|
+
}, memoryAccess);
|
|
65
65
|
if (!admitted.claimed) {
|
|
66
66
|
return {
|
|
67
67
|
accepted: false,
|
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
const { openCognitiveStateStore } = require('./cognitive-state-store.cjs');
|
|
4
4
|
|
|
5
|
-
const COGNITIVE_MEMORY_ADAPTER_VERSION =
|
|
5
|
+
const COGNITIVE_MEMORY_ADAPTER_VERSION = 2;
|
|
6
6
|
const KIND_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
7
|
+
const ACCESS_KEYS = Object.freeze([
|
|
8
|
+
'actorId', 'agentId', 'channelId', 'conversationId', 'permissionContext',
|
|
9
|
+
'portalId', 'requestedScope', 'tenantId', 'userId',
|
|
10
|
+
]);
|
|
11
|
+
const PERMISSION_KEYS = Object.freeze(['authority', 'decision', 'receiptId']);
|
|
7
12
|
const REQUIRED_METHODS = Object.freeze([
|
|
8
13
|
'commit',
|
|
9
14
|
'read',
|
|
@@ -20,6 +25,50 @@ function fail(code) {
|
|
|
20
25
|
throw error;
|
|
21
26
|
}
|
|
22
27
|
|
|
28
|
+
function exactKeys(value, expected) {
|
|
29
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
30
|
+
&& Object.keys(value).sort().join('\0') === [...expected].sort().join('\0');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function safeId(value) {
|
|
34
|
+
const text = String(value ?? '').trim();
|
|
35
|
+
return KIND_RE.test(text) ? text : '';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function normalizeMemoryAccess(access, request) {
|
|
39
|
+
if (!exactKeys(access, ACCESS_KEYS) || !exactKeys(access.permissionContext, PERMISSION_KEYS)) {
|
|
40
|
+
fail('COGNITIVE_MEMORY_ACCESS_INVALID');
|
|
41
|
+
}
|
|
42
|
+
const normalized = {
|
|
43
|
+
tenantId: safeId(access.tenantId),
|
|
44
|
+
userId: safeId(access.userId),
|
|
45
|
+
actorId: safeId(access.actorId),
|
|
46
|
+
agentId: safeId(access.agentId),
|
|
47
|
+
portalId: safeId(access.portalId),
|
|
48
|
+
channelId: safeId(access.channelId),
|
|
49
|
+
conversationId: safeId(access.conversationId),
|
|
50
|
+
requestedScope: safeId(access.requestedScope),
|
|
51
|
+
permissionContext: {
|
|
52
|
+
authority: safeId(access.permissionContext.authority),
|
|
53
|
+
decision: String(access.permissionContext.decision ?? ''),
|
|
54
|
+
receiptId: safeId(access.permissionContext.receiptId),
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
if (!normalized.tenantId || !normalized.userId || !normalized.actorId || !normalized.agentId
|
|
58
|
+
|| !normalized.portalId || !normalized.channelId || !normalized.conversationId
|
|
59
|
+
|| !normalized.requestedScope || !normalized.permissionContext.authority
|
|
60
|
+
|| !normalized.permissionContext.receiptId) fail('COGNITIVE_MEMORY_ACCESS_INVALID');
|
|
61
|
+
if (normalized.permissionContext.decision !== 'passed') fail('COGNITIVE_MEMORY_ACCESS_DENIED');
|
|
62
|
+
const requestTenant = safeId(request?.tenantId);
|
|
63
|
+
const requestAgent = safeId(request?.agentId ?? request?.candidate?.responsible_agent ?? request?.claimedBy);
|
|
64
|
+
if (!requestTenant || !requestAgent
|
|
65
|
+
|| requestTenant !== normalized.tenantId || requestAgent !== normalized.agentId) {
|
|
66
|
+
fail('COGNITIVE_MEMORY_ACCESS_SCOPE_MISMATCH');
|
|
67
|
+
}
|
|
68
|
+
normalized.permissionContext = Object.freeze(normalized.permissionContext);
|
|
69
|
+
return Object.freeze(normalized);
|
|
70
|
+
}
|
|
71
|
+
|
|
23
72
|
function assertCognitiveMemoryAdapter(adapter) {
|
|
24
73
|
if (!adapter || typeof adapter !== 'object' || Array.isArray(adapter)) {
|
|
25
74
|
fail('COGNITIVE_MEMORY_ADAPTER_INVALID');
|
|
@@ -34,14 +83,35 @@ function assertCognitiveMemoryAdapter(adapter) {
|
|
|
34
83
|
return adapter;
|
|
35
84
|
}
|
|
36
85
|
|
|
86
|
+
function guardCognitiveMemoryAdapter(adapter) {
|
|
87
|
+
const raw = assertCognitiveMemoryAdapter(adapter);
|
|
88
|
+
const guarded = {
|
|
89
|
+
contractVersion: raw.contractVersion,
|
|
90
|
+
kind: raw.kind,
|
|
91
|
+
commit: (input, access) => raw.commit(input, normalizeMemoryAccess(access, input)),
|
|
92
|
+
read: (input, access) => raw.read(input, normalizeMemoryAccess(access, input)),
|
|
93
|
+
hasEvent: (input, access) => {
|
|
94
|
+
if (!exactKeys(input, ['agentId', 'eventId', 'tenantId']) || !safeId(input.eventId)) {
|
|
95
|
+
fail('COGNITIVE_MEMORY_ACCESS_INVALID');
|
|
96
|
+
}
|
|
97
|
+
return raw.hasEvent(input, normalizeMemoryAccess(access, input));
|
|
98
|
+
},
|
|
99
|
+
verify: (input, access) => raw.verify(input, normalizeMemoryAccess(access, input)),
|
|
100
|
+
claimAttention: (input, access) => raw.claimAttention(input, normalizeMemoryAccess(access, input)),
|
|
101
|
+
authorizeAttention: (input, access) => raw.authorizeAttention(input, normalizeMemoryAccess(access, input)),
|
|
102
|
+
close: () => raw.close(),
|
|
103
|
+
};
|
|
104
|
+
return Object.freeze(guarded);
|
|
105
|
+
}
|
|
106
|
+
|
|
37
107
|
function createLocalCognitiveMemoryAdapter({ home } = {}) {
|
|
38
108
|
const store = openCognitiveStateStore({ home });
|
|
39
|
-
return
|
|
109
|
+
return guardCognitiveMemoryAdapter({
|
|
40
110
|
contractVersion: COGNITIVE_MEMORY_ADAPTER_VERSION,
|
|
41
111
|
kind: 'local-cognitive-event-store',
|
|
42
112
|
commit: (input) => store.commit(input),
|
|
43
113
|
read: (input) => store.read(input),
|
|
44
|
-
hasEvent: (
|
|
114
|
+
hasEvent: (input) => store.hasEvent(input),
|
|
45
115
|
verify: (input) => store.verify(input),
|
|
46
116
|
claimAttention: (input) => store.claimAttention(input),
|
|
47
117
|
authorizeAttention: (input) => store.authorizeAttention(input),
|
|
@@ -52,7 +122,7 @@ function createLocalCognitiveMemoryAdapter({ home } = {}) {
|
|
|
52
122
|
function openCognitiveMemoryAdapter({ home, adapter } = {}) {
|
|
53
123
|
return adapter === undefined
|
|
54
124
|
? createLocalCognitiveMemoryAdapter({ home })
|
|
55
|
-
:
|
|
125
|
+
: guardCognitiveMemoryAdapter(adapter);
|
|
56
126
|
}
|
|
57
127
|
|
|
58
128
|
module.exports = {
|
|
@@ -60,5 +130,6 @@ module.exports = {
|
|
|
60
130
|
REQUIRED_METHODS,
|
|
61
131
|
assertCognitiveMemoryAdapter,
|
|
62
132
|
createLocalCognitiveMemoryAdapter,
|
|
133
|
+
normalizeMemoryAccess,
|
|
63
134
|
openCognitiveMemoryAdapter,
|
|
64
135
|
};
|
|
@@ -289,8 +289,18 @@ function openCognitiveStateStore({ home } = {}) {
|
|
|
289
289
|
};
|
|
290
290
|
}
|
|
291
291
|
|
|
292
|
-
function hasEvent(
|
|
293
|
-
|
|
292
|
+
function hasEvent(input) {
|
|
293
|
+
if (input && typeof input === 'object' && !Array.isArray(input)) {
|
|
294
|
+
const keys = Object.keys(input);
|
|
295
|
+
const event = safeId(input.eventId);
|
|
296
|
+
const tenant = safeId(input.tenantId);
|
|
297
|
+
const agent = safeId(input.agentId);
|
|
298
|
+
if (keys.length !== 3 || !keys.every((key) => ['agentId', 'eventId', 'tenantId'].includes(key))
|
|
299
|
+
|| !event || !tenant || !agent) fail('COGNITIVE_INVALID_EVENT');
|
|
300
|
+
return Boolean(db.prepare(`SELECT 1 AS found FROM cognitive_events
|
|
301
|
+
WHERE event_id = ? AND tenant_id = ? AND agent_id = ?`).get(event, tenant, agent));
|
|
302
|
+
}
|
|
303
|
+
const event = safeId(input);
|
|
294
304
|
if (!event) fail('COGNITIVE_INVALID_EVENT');
|
|
295
305
|
return Boolean(db.prepare('SELECT 1 AS found FROM cognitive_events WHERE event_id = ?').get(event));
|
|
296
306
|
}
|
|
@@ -82,6 +82,21 @@ function createCognitiveTurnLifecycle({
|
|
|
82
82
|
const runtime = safeId(runtimeId ?? `runtime-${process.pid}-${Date.now()}`);
|
|
83
83
|
if (!tenant || !agent || !runtime || typeof now !== 'function') fail('COGNITIVE_LIFECYCLE_INVALID');
|
|
84
84
|
const store = openCognitiveMemoryAdapter({ home, adapter: memoryAdapter });
|
|
85
|
+
const internalMemoryAccess = Object.freeze({
|
|
86
|
+
tenantId: tenant,
|
|
87
|
+
userId: agent,
|
|
88
|
+
actorId: agent,
|
|
89
|
+
agentId: agent,
|
|
90
|
+
portalId: 'cli',
|
|
91
|
+
channelId: 'runtime',
|
|
92
|
+
conversationId: runtime,
|
|
93
|
+
requestedScope: 'agent:memory',
|
|
94
|
+
permissionContext: Object.freeze({
|
|
95
|
+
authority: 'runtime_internal',
|
|
96
|
+
decision: 'passed',
|
|
97
|
+
receiptId: runtime,
|
|
98
|
+
}),
|
|
99
|
+
});
|
|
85
100
|
const stageTimes = new Map();
|
|
86
101
|
const stageResults = new Map();
|
|
87
102
|
|
|
@@ -104,7 +119,7 @@ function createCognitiveTurnLifecycle({
|
|
|
104
119
|
...item,
|
|
105
120
|
}));
|
|
106
121
|
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
107
|
-
const expectedVersion = store.read({ tenantId: tenant, agentId: agent }).version;
|
|
122
|
+
const expectedVersion = store.read({ tenantId: tenant, agentId: agent }, internalMemoryAccess).version;
|
|
108
123
|
try {
|
|
109
124
|
const result = store.commit({
|
|
110
125
|
tenantId: tenant,
|
|
@@ -119,7 +134,7 @@ function createCognitiveTurnLifecycle({
|
|
|
119
134
|
message_id: stageKey,
|
|
120
135
|
},
|
|
121
136
|
observations: normalized,
|
|
122
|
-
});
|
|
137
|
+
}, internalMemoryAccess);
|
|
123
138
|
stageResults.set(stageKey, result);
|
|
124
139
|
return result;
|
|
125
140
|
} catch (error) {
|
|
@@ -132,7 +147,7 @@ function createCognitiveTurnLifecycle({
|
|
|
132
147
|
function commitDurableStage(stageKey, observations) {
|
|
133
148
|
if (stageResults.has(stageKey)) return { ...stageResults.get(stageKey), idempotent: true };
|
|
134
149
|
const eventId = digestId('durable', [tenant, agent, stageKey]);
|
|
135
|
-
if (store.hasEvent(eventId)) {
|
|
150
|
+
if (store.hasEvent({ eventId, tenantId: tenant, agentId: agent }, internalMemoryAccess)) {
|
|
136
151
|
const result = { idempotent: true };
|
|
137
152
|
stageResults.set(stageKey, result);
|
|
138
153
|
return result;
|
|
@@ -143,12 +158,12 @@ function createCognitiveTurnLifecycle({
|
|
|
143
158
|
...item,
|
|
144
159
|
}));
|
|
145
160
|
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
146
|
-
if (store.hasEvent(eventId)) {
|
|
161
|
+
if (store.hasEvent({ eventId, tenantId: tenant, agentId: agent }, internalMemoryAccess)) {
|
|
147
162
|
const result = { idempotent: true };
|
|
148
163
|
stageResults.set(stageKey, result);
|
|
149
164
|
return result;
|
|
150
165
|
}
|
|
151
|
-
const expectedVersion = store.read({ tenantId: tenant, agentId: agent }).version;
|
|
166
|
+
const expectedVersion = store.read({ tenantId: tenant, agentId: agent }, internalMemoryAccess).version;
|
|
152
167
|
try {
|
|
153
168
|
const result = store.commit({
|
|
154
169
|
tenantId: tenant,
|
|
@@ -163,7 +178,7 @@ function createCognitiveTurnLifecycle({
|
|
|
163
178
|
message_id: stageKey,
|
|
164
179
|
},
|
|
165
180
|
observations: normalized,
|
|
166
|
-
});
|
|
181
|
+
}, internalMemoryAccess);
|
|
167
182
|
stageResults.set(stageKey, result);
|
|
168
183
|
return result;
|
|
169
184
|
} catch (error) {
|
|
@@ -288,8 +303,23 @@ function createCognitiveTurnLifecycle({
|
|
|
288
303
|
...(correction ? { supersedes: targetObservationId } : { withdraws: targetObservationId }),
|
|
289
304
|
};
|
|
290
305
|
const normalizedOccurredAt = new Date(occurredAt).toISOString();
|
|
306
|
+
const revisionMemoryAccess = {
|
|
307
|
+
tenantId: tenant,
|
|
308
|
+
userId: normalizedSource.actor_id,
|
|
309
|
+
actorId: normalizedSource.actor_id,
|
|
310
|
+
agentId: agent,
|
|
311
|
+
portalId: normalizedSource.provider,
|
|
312
|
+
channelId: normalizedSource.provider,
|
|
313
|
+
conversationId: normalizedSource.context_id,
|
|
314
|
+
requestedScope: scope,
|
|
315
|
+
permissionContext: {
|
|
316
|
+
authority: input.authority,
|
|
317
|
+
decision: 'passed',
|
|
318
|
+
receiptId: requestId,
|
|
319
|
+
},
|
|
320
|
+
};
|
|
291
321
|
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
292
|
-
const current = store.read({ tenantId: tenant, agentId: agent });
|
|
322
|
+
const current = store.read({ tenantId: tenant, agentId: agent }, revisionMemoryAccess);
|
|
293
323
|
const existing = current.observations.find((item) => item.observation_id === observationId);
|
|
294
324
|
if (existing) {
|
|
295
325
|
const matches = existing.domain === observation.domain && existing.key === observation.key
|
|
@@ -317,7 +347,7 @@ function createCognitiveTurnLifecycle({
|
|
|
317
347
|
occurredAt: normalizedOccurredAt,
|
|
318
348
|
source: normalizedSource,
|
|
319
349
|
observations: [observation],
|
|
320
|
-
});
|
|
350
|
+
}, revisionMemoryAccess);
|
|
321
351
|
} catch (error) {
|
|
322
352
|
if (error?.code !== 'COGNITIVE_VERSION_CONFLICT' || attempt === 3) throw error;
|
|
323
353
|
}
|
|
@@ -414,7 +444,7 @@ function createCognitiveTurnLifecycle({
|
|
|
414
444
|
if (!exactKeys(input, new Set(['turnId', 'focusScopes']))) fail('COGNITIVE_LIFECYCLE_INVALID');
|
|
415
445
|
const turnId = safeTurnId(input.turnId);
|
|
416
446
|
if (turnId === null) fail('COGNITIVE_LIFECYCLE_INVALID');
|
|
417
|
-
const state = store.read({ tenantId: tenant, agentId: agent });
|
|
447
|
+
const state = store.read({ tenantId: tenant, agentId: agent }, internalMemoryAccess);
|
|
418
448
|
const continuity = buildCognitiveContextProjection(state, {
|
|
419
449
|
currentTurnId: turnId,
|
|
420
450
|
currentRuntimeId: runtime,
|
|
@@ -424,12 +454,30 @@ function createCognitiveTurnLifecycle({
|
|
|
424
454
|
}
|
|
425
455
|
|
|
426
456
|
function authorizeAttention(input) {
|
|
457
|
+
const candidate = input?.candidate;
|
|
458
|
+
const authorization = input?.authorization;
|
|
459
|
+
const memoryAccess = {
|
|
460
|
+
tenantId: tenant,
|
|
461
|
+
userId: String(candidate?.subject_id ?? ''),
|
|
462
|
+
actorId: agent,
|
|
463
|
+
agentId: agent,
|
|
464
|
+
portalId: 'cli',
|
|
465
|
+
channelId: String(input?.channel ?? ''),
|
|
466
|
+
conversationId: runtime,
|
|
467
|
+
requestedScope: String(candidate?.evidence_scope ?? ''),
|
|
468
|
+
permissionContext: {
|
|
469
|
+
authority: String(authorization?.authority ?? ''),
|
|
470
|
+
decision: authorization?.decision === 'passed' ? 'passed' : 'blocked',
|
|
471
|
+
receiptId: String(authorization?.receiptId ?? ''),
|
|
472
|
+
},
|
|
473
|
+
};
|
|
427
474
|
return authorizeAttentionCandidate({
|
|
428
475
|
store,
|
|
429
476
|
tenantId: tenant,
|
|
430
477
|
currentAgent: agent,
|
|
431
478
|
now,
|
|
432
479
|
input,
|
|
480
|
+
memoryAccess,
|
|
433
481
|
});
|
|
434
482
|
}
|
|
435
483
|
|
|
@@ -445,8 +493,8 @@ function createCognitiveTurnLifecycle({
|
|
|
445
493
|
authorizeAttention,
|
|
446
494
|
projectForTurn,
|
|
447
495
|
endTurn,
|
|
448
|
-
read: () => store.read({ tenantId: tenant, agentId: agent }),
|
|
449
|
-
verify: () => store.verify({ tenantId: tenant, agentId: agent }),
|
|
496
|
+
read: () => store.read({ tenantId: tenant, agentId: agent }, internalMemoryAccess),
|
|
497
|
+
verify: () => store.verify({ tenantId: tenant, agentId: agent }, internalMemoryAccess),
|
|
450
498
|
close: () => store.close(),
|
|
451
499
|
};
|
|
452
500
|
}
|
|
@@ -87,7 +87,24 @@ function createPersonalityMemoryAdapter({ identityRoot, memoryAdapter } = {}) {
|
|
|
87
87
|
value.tenantId, value.agentId, value.actorId, value.sourcePortal, value.sourceChannel,
|
|
88
88
|
value.conversationId, value.messageId, value.occurredAt, value.topic,
|
|
89
89
|
]);
|
|
90
|
-
|
|
90
|
+
const memoryAccess = {
|
|
91
|
+
tenantId: value.tenantId,
|
|
92
|
+
userId: value.actorId,
|
|
93
|
+
actorId: value.actorId,
|
|
94
|
+
agentId: value.agentId,
|
|
95
|
+
portalId: value.sourcePortal,
|
|
96
|
+
channelId: value.sourceChannel,
|
|
97
|
+
conversationId: value.conversationId,
|
|
98
|
+
requestedScope: relationshipScope(value.actorId),
|
|
99
|
+
permissionContext: {
|
|
100
|
+
authority: 'runtime_personality_policy',
|
|
101
|
+
decision: 'passed',
|
|
102
|
+
receiptId: eventId,
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
if (store.hasEvent({ eventId, tenantId: value.tenantId, agentId: value.agentId }, memoryAccess)) {
|
|
106
|
+
return { claimed: true, idempotent: true };
|
|
107
|
+
}
|
|
91
108
|
const claim = store.claimAttention({
|
|
92
109
|
tenantId: value.tenantId,
|
|
93
110
|
candidate: {
|
|
@@ -107,10 +124,10 @@ function createPersonalityMemoryAdapter({ identityRoot, memoryAdapter } = {}) {
|
|
|
107
124
|
},
|
|
108
125
|
claimedBy: value.agentId,
|
|
109
126
|
claimedAt: value.occurredAt,
|
|
110
|
-
});
|
|
127
|
+
}, memoryAccess);
|
|
111
128
|
if (!claim.claimed) return { claimed: false, next_allowed_at: claim.next_allowed_at };
|
|
112
129
|
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
113
|
-
const current = store.read({ tenantId: value.tenantId, agentId: value.agentId });
|
|
130
|
+
const current = store.read({ tenantId: value.tenantId, agentId: value.agentId }, memoryAccess);
|
|
114
131
|
try {
|
|
115
132
|
store.commit({
|
|
116
133
|
tenantId: value.tenantId,
|
|
@@ -133,7 +150,7 @@ function createPersonalityMemoryAdapter({ identityRoot, memoryAdapter } = {}) {
|
|
|
133
150
|
epistemic_state: 'verified',
|
|
134
151
|
scope: relationshipScope(value.actorId),
|
|
135
152
|
}],
|
|
136
|
-
});
|
|
153
|
+
}, memoryAccess);
|
|
137
154
|
return { claimed: true, idempotent: false };
|
|
138
155
|
} catch (error) {
|
|
139
156
|
if (error?.code !== 'COGNITIVE_VERSION_CONFLICT' || attempt === 2) throw error;
|