blun-king-cli 9.1.387 → 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.
@@ -2,7 +2,7 @@
2
2
 
3
3
  const { openCognitiveStateStore } = require('./cognitive-state-store.cjs');
4
4
 
5
- const COGNITIVE_MEMORY_ADAPTER_VERSION = 2;
5
+ const COGNITIVE_MEMORY_ADAPTER_VERSION = 3;
6
6
  const KIND_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
7
7
  const ACCESS_KEYS = Object.freeze([
8
8
  'actorId', 'agentId', 'channelId', 'conversationId', 'permissionContext',
@@ -69,6 +69,46 @@ function normalizeMemoryAccess(access, request) {
69
69
  return Object.freeze(normalized);
70
70
  }
71
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
+
72
112
  function assertCognitiveMemoryAdapter(adapter) {
73
113
  if (!adapter || typeof adapter !== 'object' || Array.isArray(adapter)) {
74
114
  fail('COGNITIVE_MEMORY_ADAPTER_INVALID');
@@ -88,17 +128,41 @@ function guardCognitiveMemoryAdapter(adapter) {
88
128
  const guarded = {
89
129
  contractVersion: raw.contractVersion,
90
130
  kind: raw.kind,
91
- commit: (input, access) => raw.commit(input, normalizeMemoryAccess(access, input)),
92
- read: (input, access) => raw.read(input, normalizeMemoryAccess(access, input)),
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
+ },
93
140
  hasEvent: (input, access) => {
94
- if (!exactKeys(input, ['agentId', 'eventId', 'tenantId']) || !safeId(input.eventId)) {
141
+ if (!exactKeys(input, ['agentId', 'eventId', 'tenantId', 'visibilityScope'])
142
+ || !safeId(input.eventId) || !safeId(input.visibilityScope)) {
95
143
  fail('COGNITIVE_MEMORY_ACCESS_INVALID');
96
144
  }
97
- return raw.hasEvent(input, normalizeMemoryAccess(access, input));
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);
98
165
  },
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
166
  close: () => raw.close(),
103
167
  };
104
168
  return Object.freeze(guarded);
@@ -110,7 +174,10 @@ function createLocalCognitiveMemoryAdapter({ home } = {}) {
110
174
  contractVersion: COGNITIVE_MEMORY_ADAPTER_VERSION,
111
175
  kind: 'local-cognitive-event-store',
112
176
  commit: (input) => store.commit(input),
113
- read: (input) => store.read(input),
177
+ read: (input, access) => store.read({
178
+ ...input,
179
+ visibilityScope: isInternalAgentAccess(access) ? 'agent:memory' : access.requestedScope,
180
+ }),
114
181
  hasEvent: (input) => store.hasEvent(input),
115
182
  verify: (input) => store.verify(input),
116
183
  claimAttention: (input) => store.claimAttention(input),
@@ -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
- if (!tenant || !agent) fail('COGNITIVE_INVALID_EVENT');
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 rows = db.prepare(`SELECT domain, fact_key, value_text, confidence, epistemic_state, scope, source_json, occurred_at, observation_id,
271
- supersedes_observation_id, withdraws_observation_id
272
- FROM cognitive_observations WHERE tenant_id = ? AND agent_id = ? ORDER BY occurred_at, rowid`).all(tenant, agent);
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 } : {}),
@@ -295,8 +303,16 @@ function openCognitiveStateStore({ home } = {}) {
295
303
  const event = safeId(input.eventId);
296
304
  const tenant = safeId(input.tenantId);
297
305
  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');
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
+ }
300
316
  return Boolean(db.prepare(`SELECT 1 AS found FROM cognitive_events
301
317
  WHERE event_id = ? AND tenant_id = ? AND agent_id = ?`).get(event, tenant, agent));
302
318
  }
@@ -147,7 +147,9 @@ function createCognitiveTurnLifecycle({
147
147
  function commitDurableStage(stageKey, observations) {
148
148
  if (stageResults.has(stageKey)) return { ...stageResults.get(stageKey), idempotent: true };
149
149
  const eventId = digestId('durable', [tenant, agent, stageKey]);
150
- if (store.hasEvent({ eventId, tenantId: tenant, agentId: agent }, internalMemoryAccess)) {
150
+ if (store.hasEvent({
151
+ eventId, tenantId: tenant, agentId: agent, visibilityScope: 'agent:memory',
152
+ }, internalMemoryAccess)) {
151
153
  const result = { idempotent: true };
152
154
  stageResults.set(stageKey, result);
153
155
  return result;
@@ -158,7 +160,9 @@ function createCognitiveTurnLifecycle({
158
160
  ...item,
159
161
  }));
160
162
  for (let attempt = 0; attempt < 4; attempt += 1) {
161
- if (store.hasEvent({ eventId, tenantId: tenant, agentId: agent }, internalMemoryAccess)) {
163
+ if (store.hasEvent({
164
+ eventId, tenantId: tenant, agentId: agent, visibilityScope: 'agent:memory',
165
+ }, internalMemoryAccess)) {
162
166
  const result = { idempotent: true };
163
167
  stageResults.set(stageKey, result);
164
168
  return result;
@@ -102,7 +102,10 @@ function createPersonalityMemoryAdapter({ identityRoot, memoryAdapter } = {}) {
102
102
  receiptId: eventId,
103
103
  },
104
104
  };
105
- if (store.hasEvent({ eventId, tenantId: value.tenantId, agentId: value.agentId }, memoryAccess)) {
105
+ if (store.hasEvent({
106
+ eventId, tenantId: value.tenantId, agentId: value.agentId,
107
+ visibilityScope: relationshipScope(value.actorId),
108
+ }, memoryAccess)) {
106
109
  return { claimed: true, idempotent: true };
107
110
  }
108
111
  const claim = store.claimAttention({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blun-king-cli",
3
- "version": "9.1.387",
3
+ "version": "9.1.388",
4
4
  "description": "BLUN CLI - your own AI agent with a Telegram channel. Get it done. With BLUN.",
5
5
  "license": "MIT",
6
6
  "bin": {