blun-king-cli 9.1.362 → 9.1.364
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.
|
@@ -14,8 +14,12 @@ function compareVariants(left, right) {
|
|
|
14
14
|
|
|
15
15
|
function resolveCognitiveEvidenceGroup(entries) {
|
|
16
16
|
if (!Array.isArray(entries) || entries.length === 0) return null;
|
|
17
|
-
const
|
|
18
|
-
const
|
|
17
|
+
const withdrawals = entries.filter((item) => Boolean(item.withdraws));
|
|
18
|
+
const deletionCutoff = withdrawals.length > 0
|
|
19
|
+
? Math.max(...withdrawals.map((item) => item.occurredAt)) : Number.NEGATIVE_INFINITY;
|
|
20
|
+
const evidence = entries.filter((item) => !item.withdraws && item.occurredAt > deletionCutoff);
|
|
21
|
+
const superseded = new Set(evidence.map((item) => item.supersedes).filter(Boolean));
|
|
22
|
+
const active = evidence.filter((item) => !superseded.has(item.observationId));
|
|
19
23
|
if (active.length === 0) return null;
|
|
20
24
|
const ordered = [...active].sort((left, right) => left.occurredAt - right.occurredAt
|
|
21
25
|
|| left.index - right.index);
|
|
@@ -49,6 +49,8 @@ function buildCognitiveFocusProjection(state, { focusScopes, maxItems = 6, maxCh
|
|
|
49
49
|
const observationId = clean(item?.observation_id, 128);
|
|
50
50
|
const supersedes = item?.supersedes === null || item?.supersedes === undefined
|
|
51
51
|
? null : clean(item.supersedes, 128);
|
|
52
|
+
const withdraws = item?.withdraws === null || item?.withdraws === undefined
|
|
53
|
+
? null : clean(item.withdraws, 128);
|
|
52
54
|
const confidence = Number(item?.confidence);
|
|
53
55
|
const occurredAt = Date.parse(String(item?.occurred_at ?? ''));
|
|
54
56
|
if (!FOCUS_DOMAINS.has(domain) || !key || !value || !scope || scope === 'runtime'
|
|
@@ -56,7 +58,7 @@ function buildCognitiveFocusProjection(state, { focusScopes, maxItems = 6, maxCh
|
|
|
56
58
|
|| !Number.isFinite(occurredAt)) return;
|
|
57
59
|
const groupKey = `${scope}\0${domain}\0${key}`;
|
|
58
60
|
const existing = groups.get(groupKey) ?? [];
|
|
59
|
-
existing.push({ domain, key, value, scope, observationId, supersedes, confidence, occurredAt, index });
|
|
61
|
+
existing.push({ domain, key, value, scope, observationId, supersedes, withdraws, confidence, occurredAt, index });
|
|
60
62
|
groups.set(groupKey, existing);
|
|
61
63
|
});
|
|
62
64
|
|
|
@@ -52,7 +52,7 @@ function normalizeSource(source) {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
function normalizeObservation(value) {
|
|
55
|
-
const allowed = new Set(['observation_id', 'domain', 'key', 'value', 'confidence', 'scope', 'supersedes']);
|
|
55
|
+
const allowed = new Set(['observation_id', 'domain', 'key', 'value', 'confidence', 'scope', 'supersedes', 'withdraws']);
|
|
56
56
|
if (!exactKeys(value, allowed) || hasForbiddenKey(value)) fail('COGNITIVE_FORBIDDEN_FIELD');
|
|
57
57
|
const observation = {
|
|
58
58
|
observation_id: safeId(value.observation_id),
|
|
@@ -72,6 +72,13 @@ function normalizeObservation(value) {
|
|
|
72
72
|
observation.supersedes = safeId(value.supersedes);
|
|
73
73
|
if (!observation.supersedes || observation.confidence !== 1) fail('COGNITIVE_INVALID_CORRECTION');
|
|
74
74
|
}
|
|
75
|
+
if (value.withdraws !== undefined && value.withdraws !== null) {
|
|
76
|
+
observation.withdraws = safeId(value.withdraws);
|
|
77
|
+
if (!observation.withdraws || observation.confidence !== 1 || observation.value !== 'withdrawn') {
|
|
78
|
+
fail('COGNITIVE_INVALID_WITHDRAWAL');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (observation.supersedes && observation.withdraws) fail('COGNITIVE_INVALID_EVENT');
|
|
75
82
|
return observation;
|
|
76
83
|
}
|
|
77
84
|
|
|
@@ -148,7 +155,8 @@ function initialize(db) {
|
|
|
148
155
|
scope TEXT NOT NULL,
|
|
149
156
|
source_json TEXT NOT NULL,
|
|
150
157
|
occurred_at TEXT NOT NULL,
|
|
151
|
-
supersedes_observation_id TEXT
|
|
158
|
+
supersedes_observation_id TEXT,
|
|
159
|
+
withdraws_observation_id TEXT
|
|
152
160
|
);
|
|
153
161
|
CREATE INDEX IF NOT EXISTS cognitive_observations_stream
|
|
154
162
|
ON cognitive_observations (tenant_id, agent_id, occurred_at, observation_id);
|
|
@@ -176,6 +184,9 @@ function initialize(db) {
|
|
|
176
184
|
if (!observationColumns.some((column) => column.name === 'supersedes_observation_id')) {
|
|
177
185
|
db.exec('ALTER TABLE cognitive_observations ADD COLUMN supersedes_observation_id TEXT');
|
|
178
186
|
}
|
|
187
|
+
if (!observationColumns.some((column) => column.name === 'withdraws_observation_id')) {
|
|
188
|
+
db.exec('ALTER TABLE cognitive_observations ADD COLUMN withdraws_observation_id TEXT');
|
|
189
|
+
}
|
|
179
190
|
}
|
|
180
191
|
|
|
181
192
|
function openCognitiveStateStore({ home } = {}) {
|
|
@@ -207,8 +218,8 @@ function openCognitiveStateStore({ home } = {}) {
|
|
|
207
218
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
208
219
|
.run(normalized.event_id, normalized.tenant_id, normalized.agent_id, actualVersion, newVersion, normalized.occurred_at, payload, previousHash, eventHash);
|
|
209
220
|
const insertObservation = db.prepare(`INSERT INTO cognitive_observations
|
|
210
|
-
(observation_id, event_id, tenant_id, agent_id, domain, fact_key, value_text, confidence, scope, source_json, occurred_at, supersedes_observation_id)
|
|
211
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
221
|
+
(observation_id, event_id, tenant_id, agent_id, domain, fact_key, value_text, confidence, scope, source_json, occurred_at, supersedes_observation_id, withdraws_observation_id)
|
|
222
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
212
223
|
const sourceJson = JSON.stringify(normalized.source);
|
|
213
224
|
for (const observation of normalized.observations) {
|
|
214
225
|
if (observation.supersedes) {
|
|
@@ -218,9 +229,16 @@ function openCognitiveStateStore({ home } = {}) {
|
|
|
218
229
|
|| target.domain !== observation.domain || target.fact_key !== observation.key
|
|
219
230
|
|| target.scope !== observation.scope) fail('COGNITIVE_INVALID_CORRECTION');
|
|
220
231
|
}
|
|
232
|
+
if (observation.withdraws) {
|
|
233
|
+
const target = db.prepare(`SELECT tenant_id, agent_id, domain, fact_key, scope
|
|
234
|
+
FROM cognitive_observations WHERE observation_id = ?`).get(observation.withdraws);
|
|
235
|
+
if (!target || target.tenant_id !== normalized.tenant_id || target.agent_id !== normalized.agent_id
|
|
236
|
+
|| target.domain !== observation.domain || target.fact_key !== observation.key
|
|
237
|
+
|| target.scope !== observation.scope) fail('COGNITIVE_INVALID_WITHDRAWAL');
|
|
238
|
+
}
|
|
221
239
|
insertObservation.run(observation.observation_id, normalized.event_id, normalized.tenant_id, normalized.agent_id,
|
|
222
240
|
observation.domain, observation.key, observation.value, observation.confidence, observation.scope, sourceJson,
|
|
223
|
-
normalized.occurred_at, observation.supersedes ?? null);
|
|
241
|
+
normalized.occurred_at, observation.supersedes ?? null, observation.withdraws ?? null);
|
|
224
242
|
}
|
|
225
243
|
db.prepare(`INSERT INTO cognitive_streams (tenant_id, agent_id, version, updated_at) VALUES (?, ?, ?, ?)
|
|
226
244
|
ON CONFLICT(tenant_id, agent_id) DO UPDATE SET version = excluded.version, updated_at = excluded.updated_at`)
|
|
@@ -239,7 +257,7 @@ function openCognitiveStateStore({ home } = {}) {
|
|
|
239
257
|
if (!tenant || !agent) fail('COGNITIVE_INVALID_EVENT');
|
|
240
258
|
const stream = db.prepare('SELECT version, updated_at FROM cognitive_streams WHERE tenant_id = ? AND agent_id = ?').get(tenant, agent);
|
|
241
259
|
const rows = db.prepare(`SELECT domain, fact_key, value_text, confidence, scope, source_json, occurred_at, observation_id,
|
|
242
|
-
supersedes_observation_id
|
|
260
|
+
supersedes_observation_id, withdraws_observation_id
|
|
243
261
|
FROM cognitive_observations WHERE tenant_id = ? AND agent_id = ? ORDER BY occurred_at, rowid`).all(tenant, agent);
|
|
244
262
|
return {
|
|
245
263
|
version: Number(stream?.version ?? 0),
|
|
@@ -254,6 +272,7 @@ function openCognitiveStateStore({ home } = {}) {
|
|
|
254
272
|
source: JSON.parse(row.source_json),
|
|
255
273
|
occurred_at: row.occurred_at,
|
|
256
274
|
supersedes: row.supersedes_observation_id ?? null,
|
|
275
|
+
withdraws: row.withdraws_observation_id ?? null,
|
|
257
276
|
})),
|
|
258
277
|
};
|
|
259
278
|
}
|
|
@@ -230,6 +230,94 @@ function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now
|
|
|
230
230
|
return commitDurableStage(`focus-${input.snapshotId}`, observations);
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
function commitExplicitFocusRevision(kind, input) {
|
|
234
|
+
const correction = kind === 'correction';
|
|
235
|
+
const allowed = correction
|
|
236
|
+
? new Set(['requestId', 'targetObservationId', 'domain', 'key', 'value', 'scope', 'authority', 'confirmation', 'occurredAt', 'source'])
|
|
237
|
+
: new Set(['requestId', 'targetObservationId', 'domain', 'key', 'scope', 'authority', 'confirmation', 'occurredAt', 'source']);
|
|
238
|
+
if (!exactKeys(input, allowed)) fail('COGNITIVE_REVISION_INVALID');
|
|
239
|
+
const requestId = safeId(input.requestId);
|
|
240
|
+
const targetObservationId = safeId(input.targetObservationId);
|
|
241
|
+
const domain = String(input.domain ?? '');
|
|
242
|
+
const key = cleanLabel(input.key, 128);
|
|
243
|
+
const scope = cleanLabel(input.scope, 128);
|
|
244
|
+
const occurredAt = String(input.occurredAt ?? '').trim();
|
|
245
|
+
const source = input.source;
|
|
246
|
+
if (input.authority !== 'runtime_user_prompt_hook' || input.confirmation !== 'explicit_user_request') {
|
|
247
|
+
fail('COGNITIVE_REVISION_EXPLICIT_USER_REQUIRED');
|
|
248
|
+
}
|
|
249
|
+
if (!requestId || !targetObservationId || !FOCUS_DOMAINS.has(domain) || !key
|
|
250
|
+
|| AUTHORITY_KEY_RE.test(key) || !scope || scope === 'runtime'
|
|
251
|
+
|| Number.isNaN(Date.parse(occurredAt))
|
|
252
|
+
|| !exactKeys(source, new Set(['provider', 'actorId', 'contextId', 'messageId']))) {
|
|
253
|
+
fail('COGNITIVE_REVISION_INVALID');
|
|
254
|
+
}
|
|
255
|
+
const normalizedSource = {
|
|
256
|
+
provider: safeId(source.provider),
|
|
257
|
+
actor_id: safeId(source.actorId),
|
|
258
|
+
context_id: safeId(source.contextId),
|
|
259
|
+
message_id: safeId(source.messageId),
|
|
260
|
+
};
|
|
261
|
+
if (Object.values(normalizedSource).some((value) => !value)) fail('COGNITIVE_REVISION_INVALID');
|
|
262
|
+
const value = correction ? cleanLabel(input.value, 512) : 'withdrawn';
|
|
263
|
+
if (!value) fail('COGNITIVE_REVISION_INVALID');
|
|
264
|
+
const eventId = digestId('revision', [tenant, agent, kind, requestId]);
|
|
265
|
+
const observationId = digestId('revisionobs', [eventId]);
|
|
266
|
+
const observation = {
|
|
267
|
+
observation_id: observationId,
|
|
268
|
+
domain,
|
|
269
|
+
key,
|
|
270
|
+
value,
|
|
271
|
+
confidence: 1,
|
|
272
|
+
scope,
|
|
273
|
+
...(correction ? { supersedes: targetObservationId } : { withdraws: targetObservationId }),
|
|
274
|
+
};
|
|
275
|
+
const normalizedOccurredAt = new Date(occurredAt).toISOString();
|
|
276
|
+
for (let attempt = 0; attempt < 4; attempt += 1) {
|
|
277
|
+
const current = store.read({ tenantId: tenant, agentId: agent });
|
|
278
|
+
const existing = current.observations.find((item) => item.observation_id === observationId);
|
|
279
|
+
if (existing) {
|
|
280
|
+
const matches = existing.domain === observation.domain && existing.key === observation.key
|
|
281
|
+
&& existing.value === observation.value && existing.confidence === 1
|
|
282
|
+
&& existing.scope === observation.scope && existing.occurred_at === normalizedOccurredAt
|
|
283
|
+
&& existing.supersedes === (observation.supersedes ?? null)
|
|
284
|
+
&& existing.withdraws === (observation.withdraws ?? null)
|
|
285
|
+
&& existing.source.provider === normalizedSource.provider
|
|
286
|
+
&& existing.source.actor_id === normalizedSource.actor_id
|
|
287
|
+
&& existing.source.context_id === normalizedSource.context_id
|
|
288
|
+
&& existing.source.message_id === normalizedSource.message_id;
|
|
289
|
+
if (!matches) fail('COGNITIVE_REVISION_REQUEST_REUSE');
|
|
290
|
+
return { version: current.version, idempotent: true };
|
|
291
|
+
}
|
|
292
|
+
const target = current.observations.find((item) => item.observation_id === targetObservationId);
|
|
293
|
+
if (target && Date.parse(normalizedOccurredAt) < Date.parse(target.occurred_at)) {
|
|
294
|
+
fail('COGNITIVE_REVISION_TIME_ORDER');
|
|
295
|
+
}
|
|
296
|
+
try {
|
|
297
|
+
return store.commit({
|
|
298
|
+
tenantId: tenant,
|
|
299
|
+
agentId: agent,
|
|
300
|
+
eventId,
|
|
301
|
+
expectedVersion: current.version,
|
|
302
|
+
occurredAt: normalizedOccurredAt,
|
|
303
|
+
source: normalizedSource,
|
|
304
|
+
observations: [observation],
|
|
305
|
+
});
|
|
306
|
+
} catch (error) {
|
|
307
|
+
if (error?.code !== 'COGNITIVE_VERSION_CONFLICT' || attempt === 3) throw error;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
fail('COGNITIVE_VERSION_CONFLICT');
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function correctFocusObservation(input) {
|
|
314
|
+
return commitExplicitFocusRevision('correction', input);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function withdrawFocusObservation(input) {
|
|
318
|
+
return commitExplicitFocusRevision('withdrawal', input);
|
|
319
|
+
}
|
|
320
|
+
|
|
233
321
|
function toolFields(input, allowedKeys) {
|
|
234
322
|
if (!exactKeys(input, allowedKeys)) fail('COGNITIVE_LIFECYCLE_INVALID');
|
|
235
323
|
const turnId = safeTurnId(input.turnId);
|
|
@@ -337,6 +425,8 @@ function createCognitiveTurnLifecycle({ home, tenantId, agentId, runtimeId, now
|
|
|
337
425
|
recordToolResult,
|
|
338
426
|
recordToolBatch,
|
|
339
427
|
recordFocusSnapshot,
|
|
428
|
+
correctFocusObservation,
|
|
429
|
+
withdrawFocusObservation,
|
|
340
430
|
authorizeAttention,
|
|
341
431
|
projectForTurn,
|
|
342
432
|
endTurn,
|