blun-king-cli 9.1.386 → 9.1.388
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 = 3;
|
|
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,90 @@ 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
|
+
|
|
72
|
+
function isInternalAgentAccess(access) {
|
|
73
|
+
return access.userId === access.agentId
|
|
74
|
+
&& access.actorId === access.agentId
|
|
75
|
+
&& access.portalId === 'cli'
|
|
76
|
+
&& access.channelId === 'runtime'
|
|
77
|
+
&& access.requestedScope === 'agent:memory'
|
|
78
|
+
&& access.permissionContext.authority === 'runtime_internal'
|
|
79
|
+
&& access.permissionContext.receiptId === access.conversationId;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function assertVisibleScope(scope, access) {
|
|
83
|
+
if (!isInternalAgentAccess(access) && safeId(scope) !== access.requestedScope) {
|
|
84
|
+
fail('COGNITIVE_MEMORY_VISIBILITY_DENIED');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function assertCommitAccess(input, access) {
|
|
89
|
+
if (isInternalAgentAccess(access)) return;
|
|
90
|
+
if (!Array.isArray(input?.observations) || input.observations.length < 1) {
|
|
91
|
+
fail('COGNITIVE_MEMORY_VISIBILITY_DENIED');
|
|
92
|
+
}
|
|
93
|
+
for (const observation of input.observations) assertVisibleScope(observation?.scope, access);
|
|
94
|
+
if (safeId(input?.source?.provider) !== access.portalId
|
|
95
|
+
|| safeId(input?.source?.actor_id) !== access.actorId
|
|
96
|
+
|| safeId(input?.source?.context_id) !== access.conversationId) {
|
|
97
|
+
fail('COGNITIVE_MEMORY_SOURCE_MISMATCH');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function projectReadableState(state, access) {
|
|
102
|
+
if (isInternalAgentAccess(access)) return state;
|
|
103
|
+
if (!state || typeof state !== 'object' || !Array.isArray(state.observations)) {
|
|
104
|
+
fail('COGNITIVE_MEMORY_ADAPTER_INVALID');
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
...state,
|
|
108
|
+
observations: state.observations.filter((item) => safeId(item?.scope) === access.requestedScope),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
23
112
|
function assertCognitiveMemoryAdapter(adapter) {
|
|
24
113
|
if (!adapter || typeof adapter !== 'object' || Array.isArray(adapter)) {
|
|
25
114
|
fail('COGNITIVE_MEMORY_ADAPTER_INVALID');
|
|
@@ -34,14 +123,62 @@ function assertCognitiveMemoryAdapter(adapter) {
|
|
|
34
123
|
return adapter;
|
|
35
124
|
}
|
|
36
125
|
|
|
126
|
+
function guardCognitiveMemoryAdapter(adapter) {
|
|
127
|
+
const raw = assertCognitiveMemoryAdapter(adapter);
|
|
128
|
+
const guarded = {
|
|
129
|
+
contractVersion: raw.contractVersion,
|
|
130
|
+
kind: raw.kind,
|
|
131
|
+
commit: (input, access) => {
|
|
132
|
+
const normalizedAccess = normalizeMemoryAccess(access, input);
|
|
133
|
+
assertCommitAccess(input, normalizedAccess);
|
|
134
|
+
return raw.commit(input, normalizedAccess);
|
|
135
|
+
},
|
|
136
|
+
read: (input, access) => {
|
|
137
|
+
const normalizedAccess = normalizeMemoryAccess(access, input);
|
|
138
|
+
return projectReadableState(raw.read(input, normalizedAccess), normalizedAccess);
|
|
139
|
+
},
|
|
140
|
+
hasEvent: (input, access) => {
|
|
141
|
+
if (!exactKeys(input, ['agentId', 'eventId', 'tenantId', 'visibilityScope'])
|
|
142
|
+
|| !safeId(input.eventId) || !safeId(input.visibilityScope)) {
|
|
143
|
+
fail('COGNITIVE_MEMORY_ACCESS_INVALID');
|
|
144
|
+
}
|
|
145
|
+
const normalizedAccess = normalizeMemoryAccess(access, input);
|
|
146
|
+
assertVisibleScope(input.visibilityScope, normalizedAccess);
|
|
147
|
+
return raw.hasEvent(input, normalizedAccess);
|
|
148
|
+
},
|
|
149
|
+
verify: (input, access) => {
|
|
150
|
+
const normalizedAccess = normalizeMemoryAccess(access, input);
|
|
151
|
+
const result = raw.verify(input, normalizedAccess);
|
|
152
|
+
if (isInternalAgentAccess(normalizedAccess)) return result;
|
|
153
|
+
if (!result || typeof result.valid !== 'boolean') fail('COGNITIVE_MEMORY_ADAPTER_INVALID');
|
|
154
|
+
return { valid: result.valid };
|
|
155
|
+
},
|
|
156
|
+
claimAttention: (input, access) => {
|
|
157
|
+
const normalizedAccess = normalizeMemoryAccess(access, input);
|
|
158
|
+
assertVisibleScope(input?.candidate?.evidence_scope, normalizedAccess);
|
|
159
|
+
return raw.claimAttention(input, normalizedAccess);
|
|
160
|
+
},
|
|
161
|
+
authorizeAttention: (input, access) => {
|
|
162
|
+
const normalizedAccess = normalizeMemoryAccess(access, input);
|
|
163
|
+
assertVisibleScope(input?.candidate?.evidence_scope, normalizedAccess);
|
|
164
|
+
return raw.authorizeAttention(input, normalizedAccess);
|
|
165
|
+
},
|
|
166
|
+
close: () => raw.close(),
|
|
167
|
+
};
|
|
168
|
+
return Object.freeze(guarded);
|
|
169
|
+
}
|
|
170
|
+
|
|
37
171
|
function createLocalCognitiveMemoryAdapter({ home } = {}) {
|
|
38
172
|
const store = openCognitiveStateStore({ home });
|
|
39
|
-
return
|
|
173
|
+
return guardCognitiveMemoryAdapter({
|
|
40
174
|
contractVersion: COGNITIVE_MEMORY_ADAPTER_VERSION,
|
|
41
175
|
kind: 'local-cognitive-event-store',
|
|
42
176
|
commit: (input) => store.commit(input),
|
|
43
|
-
read: (input) => store.read(
|
|
44
|
-
|
|
177
|
+
read: (input, access) => store.read({
|
|
178
|
+
...input,
|
|
179
|
+
visibilityScope: isInternalAgentAccess(access) ? 'agent:memory' : access.requestedScope,
|
|
180
|
+
}),
|
|
181
|
+
hasEvent: (input) => store.hasEvent(input),
|
|
45
182
|
verify: (input) => store.verify(input),
|
|
46
183
|
claimAttention: (input) => store.claimAttention(input),
|
|
47
184
|
authorizeAttention: (input) => store.authorizeAttention(input),
|
|
@@ -52,7 +189,7 @@ function createLocalCognitiveMemoryAdapter({ home } = {}) {
|
|
|
52
189
|
function openCognitiveMemoryAdapter({ home, adapter } = {}) {
|
|
53
190
|
return adapter === undefined
|
|
54
191
|
? createLocalCognitiveMemoryAdapter({ home })
|
|
55
|
-
:
|
|
192
|
+
: guardCognitiveMemoryAdapter(adapter);
|
|
56
193
|
}
|
|
57
194
|
|
|
58
195
|
module.exports = {
|
|
@@ -60,5 +197,6 @@ module.exports = {
|
|
|
60
197
|
REQUIRED_METHODS,
|
|
61
198
|
assertCognitiveMemoryAdapter,
|
|
62
199
|
createLocalCognitiveMemoryAdapter,
|
|
200
|
+
normalizeMemoryAccess,
|
|
63
201
|
openCognitiveMemoryAdapter,
|
|
64
202
|
};
|
|
@@ -167,6 +167,8 @@ function initialize(db) {
|
|
|
167
167
|
);
|
|
168
168
|
CREATE INDEX IF NOT EXISTS cognitive_observations_stream
|
|
169
169
|
ON cognitive_observations (tenant_id, agent_id, occurred_at, observation_id);
|
|
170
|
+
CREATE INDEX IF NOT EXISTS cognitive_observations_visibility
|
|
171
|
+
ON cognitive_observations (tenant_id, agent_id, scope, occurred_at, observation_id);
|
|
170
172
|
CREATE TABLE IF NOT EXISTS cognitive_attention_claims (
|
|
171
173
|
tenant_id TEXT NOT NULL,
|
|
172
174
|
candidate_id TEXT NOT NULL,
|
|
@@ -262,14 +264,20 @@ function openCognitiveStateStore({ home } = {}) {
|
|
|
262
264
|
}
|
|
263
265
|
}
|
|
264
266
|
|
|
265
|
-
function read({ tenantId, agentId } = {}) {
|
|
267
|
+
function read({ tenantId, agentId, visibilityScope } = {}) {
|
|
266
268
|
const tenant = safeId(tenantId);
|
|
267
269
|
const agent = safeId(agentId);
|
|
268
|
-
|
|
270
|
+
const requestedVisibility = visibilityScope === undefined ? '' : safeId(visibilityScope);
|
|
271
|
+
if (!tenant || !agent || (visibilityScope !== undefined && !requestedVisibility)) {
|
|
272
|
+
fail('COGNITIVE_INVALID_EVENT');
|
|
273
|
+
}
|
|
269
274
|
const stream = db.prepare('SELECT version, updated_at FROM cognitive_streams WHERE tenant_id = ? AND agent_id = ?').get(tenant, agent);
|
|
270
|
-
const
|
|
271
|
-
supersedes_observation_id, withdraws_observation_id
|
|
272
|
-
|
|
275
|
+
const select = `SELECT domain, fact_key, value_text, confidence, epistemic_state, scope, source_json, occurred_at, observation_id,
|
|
276
|
+
supersedes_observation_id, withdraws_observation_id FROM cognitive_observations`;
|
|
277
|
+
const rows = requestedVisibility && requestedVisibility !== 'agent:memory'
|
|
278
|
+
? db.prepare(`${select} WHERE tenant_id = ? AND agent_id = ? AND scope = ? ORDER BY occurred_at, rowid`)
|
|
279
|
+
.all(tenant, agent, requestedVisibility)
|
|
280
|
+
: db.prepare(`${select} WHERE tenant_id = ? AND agent_id = ? ORDER BY occurred_at, rowid`).all(tenant, agent);
|
|
273
281
|
return {
|
|
274
282
|
version: Number(stream?.version ?? 0),
|
|
275
283
|
...(stream?.updated_at ? { updated_at: stream.updated_at } : {}),
|
|
@@ -289,8 +297,26 @@ function openCognitiveStateStore({ home } = {}) {
|
|
|
289
297
|
};
|
|
290
298
|
}
|
|
291
299
|
|
|
292
|
-
function hasEvent(
|
|
293
|
-
|
|
300
|
+
function hasEvent(input) {
|
|
301
|
+
if (input && typeof input === 'object' && !Array.isArray(input)) {
|
|
302
|
+
const keys = Object.keys(input);
|
|
303
|
+
const event = safeId(input.eventId);
|
|
304
|
+
const tenant = safeId(input.tenantId);
|
|
305
|
+
const agent = safeId(input.agentId);
|
|
306
|
+
const visibilityScope = safeId(input.visibilityScope);
|
|
307
|
+
if (keys.length !== 4
|
|
308
|
+
|| !keys.every((key) => ['agentId', 'eventId', 'tenantId', 'visibilityScope'].includes(key))
|
|
309
|
+
|| !event || !tenant || !agent || !visibilityScope) fail('COGNITIVE_INVALID_EVENT');
|
|
310
|
+
if (visibilityScope !== 'agent:memory') {
|
|
311
|
+
return Boolean(db.prepare(`SELECT 1 AS found FROM cognitive_events AS event
|
|
312
|
+
INNER JOIN cognitive_observations AS observation ON observation.event_id = event.event_id
|
|
313
|
+
WHERE event.event_id = ? AND event.tenant_id = ? AND event.agent_id = ? AND observation.scope = ?
|
|
314
|
+
LIMIT 1`).get(event, tenant, agent, visibilityScope));
|
|
315
|
+
}
|
|
316
|
+
return Boolean(db.prepare(`SELECT 1 AS found FROM cognitive_events
|
|
317
|
+
WHERE event_id = ? AND tenant_id = ? AND agent_id = ?`).get(event, tenant, agent));
|
|
318
|
+
}
|
|
319
|
+
const event = safeId(input);
|
|
294
320
|
if (!event) fail('COGNITIVE_INVALID_EVENT');
|
|
295
321
|
return Boolean(db.prepare('SELECT 1 AS found FROM cognitive_events WHERE event_id = ?').get(event));
|
|
296
322
|
}
|
|
@@ -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,9 @@ 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(
|
|
150
|
+
if (store.hasEvent({
|
|
151
|
+
eventId, tenantId: tenant, agentId: agent, visibilityScope: 'agent:memory',
|
|
152
|
+
}, internalMemoryAccess)) {
|
|
136
153
|
const result = { idempotent: true };
|
|
137
154
|
stageResults.set(stageKey, result);
|
|
138
155
|
return result;
|
|
@@ -143,12 +160,14 @@ function createCognitiveTurnLifecycle({
|
|
|
143
160
|
...item,
|
|
144
161
|
}));
|
|
145
162
|
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
146
|
-
if (store.hasEvent(
|
|
163
|
+
if (store.hasEvent({
|
|
164
|
+
eventId, tenantId: tenant, agentId: agent, visibilityScope: 'agent:memory',
|
|
165
|
+
}, internalMemoryAccess)) {
|
|
147
166
|
const result = { idempotent: true };
|
|
148
167
|
stageResults.set(stageKey, result);
|
|
149
168
|
return result;
|
|
150
169
|
}
|
|
151
|
-
const expectedVersion = store.read({ tenantId: tenant, agentId: agent }).version;
|
|
170
|
+
const expectedVersion = store.read({ tenantId: tenant, agentId: agent }, internalMemoryAccess).version;
|
|
152
171
|
try {
|
|
153
172
|
const result = store.commit({
|
|
154
173
|
tenantId: tenant,
|
|
@@ -163,7 +182,7 @@ function createCognitiveTurnLifecycle({
|
|
|
163
182
|
message_id: stageKey,
|
|
164
183
|
},
|
|
165
184
|
observations: normalized,
|
|
166
|
-
});
|
|
185
|
+
}, internalMemoryAccess);
|
|
167
186
|
stageResults.set(stageKey, result);
|
|
168
187
|
return result;
|
|
169
188
|
} catch (error) {
|
|
@@ -288,8 +307,23 @@ function createCognitiveTurnLifecycle({
|
|
|
288
307
|
...(correction ? { supersedes: targetObservationId } : { withdraws: targetObservationId }),
|
|
289
308
|
};
|
|
290
309
|
const normalizedOccurredAt = new Date(occurredAt).toISOString();
|
|
310
|
+
const revisionMemoryAccess = {
|
|
311
|
+
tenantId: tenant,
|
|
312
|
+
userId: normalizedSource.actor_id,
|
|
313
|
+
actorId: normalizedSource.actor_id,
|
|
314
|
+
agentId: agent,
|
|
315
|
+
portalId: normalizedSource.provider,
|
|
316
|
+
channelId: normalizedSource.provider,
|
|
317
|
+
conversationId: normalizedSource.context_id,
|
|
318
|
+
requestedScope: scope,
|
|
319
|
+
permissionContext: {
|
|
320
|
+
authority: input.authority,
|
|
321
|
+
decision: 'passed',
|
|
322
|
+
receiptId: requestId,
|
|
323
|
+
},
|
|
324
|
+
};
|
|
291
325
|
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
292
|
-
const current = store.read({ tenantId: tenant, agentId: agent });
|
|
326
|
+
const current = store.read({ tenantId: tenant, agentId: agent }, revisionMemoryAccess);
|
|
293
327
|
const existing = current.observations.find((item) => item.observation_id === observationId);
|
|
294
328
|
if (existing) {
|
|
295
329
|
const matches = existing.domain === observation.domain && existing.key === observation.key
|
|
@@ -317,7 +351,7 @@ function createCognitiveTurnLifecycle({
|
|
|
317
351
|
occurredAt: normalizedOccurredAt,
|
|
318
352
|
source: normalizedSource,
|
|
319
353
|
observations: [observation],
|
|
320
|
-
});
|
|
354
|
+
}, revisionMemoryAccess);
|
|
321
355
|
} catch (error) {
|
|
322
356
|
if (error?.code !== 'COGNITIVE_VERSION_CONFLICT' || attempt === 3) throw error;
|
|
323
357
|
}
|
|
@@ -414,7 +448,7 @@ function createCognitiveTurnLifecycle({
|
|
|
414
448
|
if (!exactKeys(input, new Set(['turnId', 'focusScopes']))) fail('COGNITIVE_LIFECYCLE_INVALID');
|
|
415
449
|
const turnId = safeTurnId(input.turnId);
|
|
416
450
|
if (turnId === null) fail('COGNITIVE_LIFECYCLE_INVALID');
|
|
417
|
-
const state = store.read({ tenantId: tenant, agentId: agent });
|
|
451
|
+
const state = store.read({ tenantId: tenant, agentId: agent }, internalMemoryAccess);
|
|
418
452
|
const continuity = buildCognitiveContextProjection(state, {
|
|
419
453
|
currentTurnId: turnId,
|
|
420
454
|
currentRuntimeId: runtime,
|
|
@@ -424,12 +458,30 @@ function createCognitiveTurnLifecycle({
|
|
|
424
458
|
}
|
|
425
459
|
|
|
426
460
|
function authorizeAttention(input) {
|
|
461
|
+
const candidate = input?.candidate;
|
|
462
|
+
const authorization = input?.authorization;
|
|
463
|
+
const memoryAccess = {
|
|
464
|
+
tenantId: tenant,
|
|
465
|
+
userId: String(candidate?.subject_id ?? ''),
|
|
466
|
+
actorId: agent,
|
|
467
|
+
agentId: agent,
|
|
468
|
+
portalId: 'cli',
|
|
469
|
+
channelId: String(input?.channel ?? ''),
|
|
470
|
+
conversationId: runtime,
|
|
471
|
+
requestedScope: String(candidate?.evidence_scope ?? ''),
|
|
472
|
+
permissionContext: {
|
|
473
|
+
authority: String(authorization?.authority ?? ''),
|
|
474
|
+
decision: authorization?.decision === 'passed' ? 'passed' : 'blocked',
|
|
475
|
+
receiptId: String(authorization?.receiptId ?? ''),
|
|
476
|
+
},
|
|
477
|
+
};
|
|
427
478
|
return authorizeAttentionCandidate({
|
|
428
479
|
store,
|
|
429
480
|
tenantId: tenant,
|
|
430
481
|
currentAgent: agent,
|
|
431
482
|
now,
|
|
432
483
|
input,
|
|
484
|
+
memoryAccess,
|
|
433
485
|
});
|
|
434
486
|
}
|
|
435
487
|
|
|
@@ -445,8 +497,8 @@ function createCognitiveTurnLifecycle({
|
|
|
445
497
|
authorizeAttention,
|
|
446
498
|
projectForTurn,
|
|
447
499
|
endTurn,
|
|
448
|
-
read: () => store.read({ tenantId: tenant, agentId: agent }),
|
|
449
|
-
verify: () => store.verify({ tenantId: tenant, agentId: agent }),
|
|
500
|
+
read: () => store.read({ tenantId: tenant, agentId: agent }, internalMemoryAccess),
|
|
501
|
+
verify: () => store.verify({ tenantId: tenant, agentId: agent }, internalMemoryAccess),
|
|
450
502
|
close: () => store.close(),
|
|
451
503
|
};
|
|
452
504
|
}
|
|
@@ -87,7 +87,27 @@ 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({
|
|
106
|
+
eventId, tenantId: value.tenantId, agentId: value.agentId,
|
|
107
|
+
visibilityScope: relationshipScope(value.actorId),
|
|
108
|
+
}, memoryAccess)) {
|
|
109
|
+
return { claimed: true, idempotent: true };
|
|
110
|
+
}
|
|
91
111
|
const claim = store.claimAttention({
|
|
92
112
|
tenantId: value.tenantId,
|
|
93
113
|
candidate: {
|
|
@@ -107,10 +127,10 @@ function createPersonalityMemoryAdapter({ identityRoot, memoryAdapter } = {}) {
|
|
|
107
127
|
},
|
|
108
128
|
claimedBy: value.agentId,
|
|
109
129
|
claimedAt: value.occurredAt,
|
|
110
|
-
});
|
|
130
|
+
}, memoryAccess);
|
|
111
131
|
if (!claim.claimed) return { claimed: false, next_allowed_at: claim.next_allowed_at };
|
|
112
132
|
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
113
|
-
const current = store.read({ tenantId: value.tenantId, agentId: value.agentId });
|
|
133
|
+
const current = store.read({ tenantId: value.tenantId, agentId: value.agentId }, memoryAccess);
|
|
114
134
|
try {
|
|
115
135
|
store.commit({
|
|
116
136
|
tenantId: value.tenantId,
|
|
@@ -133,7 +153,7 @@ function createPersonalityMemoryAdapter({ identityRoot, memoryAdapter } = {}) {
|
|
|
133
153
|
epistemic_state: 'verified',
|
|
134
154
|
scope: relationshipScope(value.actorId),
|
|
135
155
|
}],
|
|
136
|
-
});
|
|
156
|
+
}, memoryAccess);
|
|
137
157
|
return { claimed: true, idempotent: false };
|
|
138
158
|
} catch (error) {
|
|
139
159
|
if (error?.code !== 'COGNITIVE_VERSION_CONFLICT' || attempt === 2) throw error;
|