blun-king-cli 9.1.388 → 9.1.390
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.
- package/bin/cognitive-memory-adapter.cjs +8 -1
- package/bin/cognitive-memory-command.cjs +3 -0
- package/bin/cognitive-state-store.cjs +43 -9
- package/bin/cognitive-turn-lifecycle.cjs +13 -2
- package/bin/identity-context-policy.cjs +2 -0
- package/bin/personality-memory-adapter.cjs +7 -1
- package/bin/relationship-curiosity-policy.cjs +3 -1
- package/package.json +1 -1
|
@@ -2,8 +2,9 @@
|
|
|
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 = 5;
|
|
6
6
|
const KIND_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
7
|
+
const RETENTION_CLASSES = new Set(['operational', 'durable', 'relationship', 'audit']);
|
|
7
8
|
const ACCESS_KEYS = Object.freeze([
|
|
8
9
|
'actorId', 'agentId', 'channelId', 'conversationId', 'permissionContext',
|
|
9
10
|
'portalId', 'requestedScope', 'tenantId', 'userId',
|
|
@@ -86,12 +87,18 @@ function assertVisibleScope(scope, access) {
|
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
function assertCommitAccess(input, access) {
|
|
90
|
+
if (Number.isNaN(Date.parse(String(input?.occurredAt ?? '')))
|
|
91
|
+
|| Number.isNaN(Date.parse(String(input?.receivedAt ?? '')))
|
|
92
|
+
|| !RETENTION_CLASSES.has(String(input?.retentionClass ?? ''))) {
|
|
93
|
+
fail('COGNITIVE_MEMORY_EVENT_ENVELOPE_INVALID');
|
|
94
|
+
}
|
|
89
95
|
if (isInternalAgentAccess(access)) return;
|
|
90
96
|
if (!Array.isArray(input?.observations) || input.observations.length < 1) {
|
|
91
97
|
fail('COGNITIVE_MEMORY_VISIBILITY_DENIED');
|
|
92
98
|
}
|
|
93
99
|
for (const observation of input.observations) assertVisibleScope(observation?.scope, access);
|
|
94
100
|
if (safeId(input?.source?.provider) !== access.portalId
|
|
101
|
+
|| safeId(input?.source?.channel_id) !== access.channelId
|
|
95
102
|
|| safeId(input?.source?.actor_id) !== access.actorId
|
|
96
103
|
|| safeId(input?.source?.context_id) !== access.conversationId) {
|
|
97
104
|
fail('COGNITIVE_MEMORY_SOURCE_MISMATCH');
|
|
@@ -110,6 +110,7 @@ function matchesRevisionReplay(items, target, command, commandSource) {
|
|
|
110
110
|
: item.withdraws === target.observationId && item.value === 'withdrawn';
|
|
111
111
|
return linked
|
|
112
112
|
&& item.source?.provider === commandSource.source.provider
|
|
113
|
+
&& item.source?.channel_id === commandSource.source.channelId
|
|
113
114
|
&& item.source?.actor_id === commandSource.source.actorId
|
|
114
115
|
&& item.source?.context_id === commandSource.source.contextId
|
|
115
116
|
&& item.source?.message_id === commandSource.source.messageId
|
|
@@ -133,6 +134,7 @@ function normalizeTelegramSource(source) {
|
|
|
133
134
|
occurredAt: timestamp,
|
|
134
135
|
source: {
|
|
135
136
|
provider: 'telegram',
|
|
137
|
+
channelId: 'direct',
|
|
136
138
|
actorId: `tg_user_${userId}`,
|
|
137
139
|
contextId: `tg_chat_${chatId}`,
|
|
138
140
|
messageId: `tg_message_${messageId}`,
|
|
@@ -153,6 +155,7 @@ function localSource({ env, sessionId, occurredAt, nonce }) {
|
|
|
153
155
|
occurredAt,
|
|
154
156
|
source: {
|
|
155
157
|
provider: 'cli',
|
|
158
|
+
channelId: 'terminal',
|
|
156
159
|
actorId: digestId('localuser', [actor]),
|
|
157
160
|
contextId: digestId('clisession', [session]),
|
|
158
161
|
messageId: digestId('cliinput', [unique]),
|
|
@@ -10,6 +10,7 @@ const DOMAINS = new Set(['self', 'world', 'team', 'goal', 'open_thread', 'assump
|
|
|
10
10
|
const EPISTEMIC_STATES = new Set([
|
|
11
11
|
'verified', 'credible_unverified', 'hypothesis', 'uncertain_memory', 'stale', 'unknown', 'legacy_unknown',
|
|
12
12
|
]);
|
|
13
|
+
const RETENTION_CLASSES = new Set(['operational', 'durable', 'relationship', 'audit']);
|
|
13
14
|
const FORBIDDEN_KEY_RE = /(?:^|_)(?:acl|api_key|capability|password|permission|secret|token)(?:_|$)/iu;
|
|
14
15
|
const MAX_EVENT_BYTES = 64 * 1024;
|
|
15
16
|
const MAX_OBSERVATIONS = 32;
|
|
@@ -42,10 +43,11 @@ function exactKeys(value, keys) {
|
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
function normalizeSource(source) {
|
|
45
|
-
const allowed = new Set(['provider', 'actor_id', 'context_id', 'message_id']);
|
|
46
|
+
const allowed = new Set(['provider', 'channel_id', 'actor_id', 'context_id', 'message_id']);
|
|
46
47
|
if (!exactKeys(source, allowed) || hasForbiddenKey(source)) fail('COGNITIVE_FORBIDDEN_FIELD');
|
|
47
48
|
const normalized = {
|
|
48
49
|
provider: safeId(source.provider),
|
|
50
|
+
channel_id: safeId(source.channel_id),
|
|
49
51
|
actor_id: safeId(source.actor_id),
|
|
50
52
|
context_id: safeId(source.context_id),
|
|
51
53
|
message_id: safeId(source.message_id),
|
|
@@ -89,13 +91,21 @@ function normalizeObservation(value) {
|
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
function normalizeEvent(input) {
|
|
94
|
+
const allowed = new Set([
|
|
95
|
+
'tenantId', 'agentId', 'eventId', 'expectedVersion', 'occurredAt', 'receivedAt',
|
|
96
|
+
'retentionClass', 'source', 'observations',
|
|
97
|
+
]);
|
|
98
|
+
if (!exactKeys(input, allowed) || hasForbiddenKey(input)) fail('COGNITIVE_FORBIDDEN_FIELD');
|
|
92
99
|
const tenantId = safeId(input.tenantId);
|
|
93
100
|
const agentId = safeId(input.agentId);
|
|
94
101
|
const eventId = safeId(input.eventId);
|
|
95
102
|
const expectedVersion = Number(input.expectedVersion);
|
|
96
103
|
const occurredAt = String(input.occurredAt ?? '').trim();
|
|
104
|
+
const receivedAt = String(input.receivedAt ?? '').trim();
|
|
105
|
+
const retentionClass = String(input.retentionClass ?? '').trim();
|
|
97
106
|
if (!tenantId || !agentId || !eventId || !Number.isSafeInteger(expectedVersion)
|
|
98
107
|
|| expectedVersion < 0 || Number.isNaN(Date.parse(occurredAt))
|
|
108
|
+
|| Number.isNaN(Date.parse(receivedAt)) || !RETENTION_CLASSES.has(retentionClass)
|
|
99
109
|
|| !Array.isArray(input.observations) || input.observations.length < 1
|
|
100
110
|
|| input.observations.length > MAX_OBSERVATIONS) fail('COGNITIVE_INVALID_EVENT');
|
|
101
111
|
const normalized = {
|
|
@@ -103,7 +113,9 @@ function normalizeEvent(input) {
|
|
|
103
113
|
agent_id: agentId,
|
|
104
114
|
event_id: eventId,
|
|
105
115
|
expected_version: expectedVersion,
|
|
106
|
-
occurred_at: occurredAt,
|
|
116
|
+
occurred_at: new Date(occurredAt).toISOString(),
|
|
117
|
+
received_at: new Date(receivedAt).toISOString(),
|
|
118
|
+
retention_class: retentionClass,
|
|
107
119
|
source: normalizeSource(input.source),
|
|
108
120
|
observations: input.observations.map(normalizeObservation),
|
|
109
121
|
};
|
|
@@ -145,6 +157,8 @@ function initialize(db) {
|
|
|
145
157
|
expected_version INTEGER NOT NULL,
|
|
146
158
|
new_version INTEGER NOT NULL,
|
|
147
159
|
occurred_at TEXT NOT NULL,
|
|
160
|
+
received_at TEXT NOT NULL,
|
|
161
|
+
retention_class TEXT NOT NULL,
|
|
148
162
|
payload_json TEXT NOT NULL,
|
|
149
163
|
previous_hash TEXT NOT NULL,
|
|
150
164
|
event_hash TEXT NOT NULL UNIQUE
|
|
@@ -162,6 +176,8 @@ function initialize(db) {
|
|
|
162
176
|
scope TEXT NOT NULL,
|
|
163
177
|
source_json TEXT NOT NULL,
|
|
164
178
|
occurred_at TEXT NOT NULL,
|
|
179
|
+
received_at TEXT NOT NULL,
|
|
180
|
+
retention_class TEXT NOT NULL,
|
|
165
181
|
supersedes_observation_id TEXT,
|
|
166
182
|
withdraws_observation_id TEXT
|
|
167
183
|
);
|
|
@@ -199,6 +215,19 @@ function initialize(db) {
|
|
|
199
215
|
if (!observationColumns.some((column) => column.name === 'epistemic_state')) {
|
|
200
216
|
db.exec("ALTER TABLE cognitive_observations ADD COLUMN epistemic_state TEXT NOT NULL DEFAULT 'legacy_unknown'");
|
|
201
217
|
}
|
|
218
|
+
if (!observationColumns.some((column) => column.name === 'received_at')) {
|
|
219
|
+
db.exec("ALTER TABLE cognitive_observations ADD COLUMN received_at TEXT NOT NULL DEFAULT ''");
|
|
220
|
+
}
|
|
221
|
+
if (!observationColumns.some((column) => column.name === 'retention_class')) {
|
|
222
|
+
db.exec("ALTER TABLE cognitive_observations ADD COLUMN retention_class TEXT NOT NULL DEFAULT 'legacy_unknown'");
|
|
223
|
+
}
|
|
224
|
+
const eventColumns = db.prepare('PRAGMA table_info(cognitive_events)').all();
|
|
225
|
+
if (!eventColumns.some((column) => column.name === 'received_at')) {
|
|
226
|
+
db.exec("ALTER TABLE cognitive_events ADD COLUMN received_at TEXT NOT NULL DEFAULT ''");
|
|
227
|
+
}
|
|
228
|
+
if (!eventColumns.some((column) => column.name === 'retention_class')) {
|
|
229
|
+
db.exec("ALTER TABLE cognitive_events ADD COLUMN retention_class TEXT NOT NULL DEFAULT 'legacy_unknown'");
|
|
230
|
+
}
|
|
202
231
|
}
|
|
203
232
|
|
|
204
233
|
function openCognitiveStateStore({ home } = {}) {
|
|
@@ -226,12 +255,13 @@ function openCognitiveStateStore({ home } = {}) {
|
|
|
226
255
|
const eventHash = crypto.createHash('sha256').update(`${previousHash}\0${payload}`).digest('hex');
|
|
227
256
|
const newVersion = actualVersion + 1;
|
|
228
257
|
db.prepare(`INSERT INTO cognitive_events
|
|
229
|
-
(event_id, tenant_id, agent_id, expected_version, new_version, occurred_at, payload_json, previous_hash, event_hash)
|
|
230
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
231
|
-
.run(normalized.event_id, normalized.tenant_id, normalized.agent_id, actualVersion, newVersion,
|
|
258
|
+
(event_id, tenant_id, agent_id, expected_version, new_version, occurred_at, received_at, retention_class, payload_json, previous_hash, event_hash)
|
|
259
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
260
|
+
.run(normalized.event_id, normalized.tenant_id, normalized.agent_id, actualVersion, newVersion,
|
|
261
|
+
normalized.occurred_at, normalized.received_at, normalized.retention_class, payload, previousHash, eventHash);
|
|
232
262
|
const insertObservation = db.prepare(`INSERT INTO cognitive_observations
|
|
233
|
-
(observation_id, event_id, tenant_id, agent_id, domain, fact_key, value_text, confidence, epistemic_state, scope, source_json, occurred_at, supersedes_observation_id, withdraws_observation_id)
|
|
234
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
263
|
+
(observation_id, event_id, tenant_id, agent_id, domain, fact_key, value_text, confidence, epistemic_state, scope, source_json, occurred_at, received_at, retention_class, supersedes_observation_id, withdraws_observation_id)
|
|
264
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`);
|
|
235
265
|
const sourceJson = JSON.stringify(normalized.source);
|
|
236
266
|
for (const observation of normalized.observations) {
|
|
237
267
|
if (observation.supersedes) {
|
|
@@ -251,7 +281,8 @@ function openCognitiveStateStore({ home } = {}) {
|
|
|
251
281
|
insertObservation.run(observation.observation_id, normalized.event_id, normalized.tenant_id, normalized.agent_id,
|
|
252
282
|
observation.domain, observation.key, observation.value, observation.confidence, observation.epistemic_state,
|
|
253
283
|
observation.scope, sourceJson,
|
|
254
|
-
normalized.occurred_at,
|
|
284
|
+
normalized.occurred_at, normalized.received_at, normalized.retention_class,
|
|
285
|
+
observation.supersedes ?? null, observation.withdraws ?? null);
|
|
255
286
|
}
|
|
256
287
|
db.prepare(`INSERT INTO cognitive_streams (tenant_id, agent_id, version, updated_at) VALUES (?, ?, ?, ?)
|
|
257
288
|
ON CONFLICT(tenant_id, agent_id) DO UPDATE SET version = excluded.version, updated_at = excluded.updated_at`)
|
|
@@ -272,7 +303,8 @@ function openCognitiveStateStore({ home } = {}) {
|
|
|
272
303
|
fail('COGNITIVE_INVALID_EVENT');
|
|
273
304
|
}
|
|
274
305
|
const stream = db.prepare('SELECT version, updated_at FROM cognitive_streams WHERE tenant_id = ? AND agent_id = ?').get(tenant, agent);
|
|
275
|
-
const select = `SELECT domain, fact_key, value_text, confidence, epistemic_state, scope, source_json, occurred_at,
|
|
306
|
+
const select = `SELECT domain, fact_key, value_text, confidence, epistemic_state, scope, source_json, occurred_at, received_at,
|
|
307
|
+
retention_class, observation_id,
|
|
276
308
|
supersedes_observation_id, withdraws_observation_id FROM cognitive_observations`;
|
|
277
309
|
const rows = requestedVisibility && requestedVisibility !== 'agent:memory'
|
|
278
310
|
? db.prepare(`${select} WHERE tenant_id = ? AND agent_id = ? AND scope = ? ORDER BY occurred_at, rowid`)
|
|
@@ -291,6 +323,8 @@ function openCognitiveStateStore({ home } = {}) {
|
|
|
291
323
|
scope: row.scope,
|
|
292
324
|
source: JSON.parse(row.source_json),
|
|
293
325
|
occurred_at: row.occurred_at,
|
|
326
|
+
received_at: row.received_at || row.occurred_at,
|
|
327
|
+
retention_class: row.retention_class || 'legacy_unknown',
|
|
294
328
|
supersedes: row.supersedes_observation_id ?? null,
|
|
295
329
|
withdraws: row.withdraws_observation_id ?? null,
|
|
296
330
|
})),
|
|
@@ -127,8 +127,11 @@ function createCognitiveTurnLifecycle({
|
|
|
127
127
|
eventId,
|
|
128
128
|
expectedVersion,
|
|
129
129
|
occurredAt,
|
|
130
|
+
receivedAt: occurredAt,
|
|
131
|
+
retentionClass: 'operational',
|
|
130
132
|
source: {
|
|
131
133
|
provider: 'runtime',
|
|
134
|
+
channel_id: 'runtime',
|
|
132
135
|
actor_id: agent,
|
|
133
136
|
context_id: runtime,
|
|
134
137
|
message_id: stageKey,
|
|
@@ -175,8 +178,11 @@ function createCognitiveTurnLifecycle({
|
|
|
175
178
|
eventId,
|
|
176
179
|
expectedVersion,
|
|
177
180
|
occurredAt,
|
|
181
|
+
receivedAt: occurredAt,
|
|
182
|
+
retentionClass: 'durable',
|
|
178
183
|
source: {
|
|
179
184
|
provider: 'runtime',
|
|
185
|
+
channel_id: 'runtime',
|
|
180
186
|
actor_id: agent,
|
|
181
187
|
context_id: 'durable-focus',
|
|
182
188
|
message_id: stageKey,
|
|
@@ -282,11 +288,12 @@ function createCognitiveTurnLifecycle({
|
|
|
282
288
|
if (!requestId || !targetObservationId || !FOCUS_DOMAINS.has(domain) || !key
|
|
283
289
|
|| AUTHORITY_KEY_RE.test(key) || !scope || scope === 'runtime'
|
|
284
290
|
|| Number.isNaN(Date.parse(occurredAt))
|
|
285
|
-
|| !exactKeys(source, new Set(['provider', 'actorId', 'contextId', 'messageId']))) {
|
|
291
|
+
|| !exactKeys(source, new Set(['provider', 'channelId', 'actorId', 'contextId', 'messageId']))) {
|
|
286
292
|
fail('COGNITIVE_REVISION_INVALID');
|
|
287
293
|
}
|
|
288
294
|
const normalizedSource = {
|
|
289
295
|
provider: safeId(source.provider),
|
|
296
|
+
channel_id: safeId(source.channelId),
|
|
290
297
|
actor_id: safeId(source.actorId),
|
|
291
298
|
context_id: safeId(source.contextId),
|
|
292
299
|
message_id: safeId(source.messageId),
|
|
@@ -307,13 +314,14 @@ function createCognitiveTurnLifecycle({
|
|
|
307
314
|
...(correction ? { supersedes: targetObservationId } : { withdraws: targetObservationId }),
|
|
308
315
|
};
|
|
309
316
|
const normalizedOccurredAt = new Date(occurredAt).toISOString();
|
|
317
|
+
const receivedAt = stageTime(`revision:${kind}:${requestId}`);
|
|
310
318
|
const revisionMemoryAccess = {
|
|
311
319
|
tenantId: tenant,
|
|
312
320
|
userId: normalizedSource.actor_id,
|
|
313
321
|
actorId: normalizedSource.actor_id,
|
|
314
322
|
agentId: agent,
|
|
315
323
|
portalId: normalizedSource.provider,
|
|
316
|
-
channelId: normalizedSource.
|
|
324
|
+
channelId: normalizedSource.channel_id,
|
|
317
325
|
conversationId: normalizedSource.context_id,
|
|
318
326
|
requestedScope: scope,
|
|
319
327
|
permissionContext: {
|
|
@@ -332,6 +340,7 @@ function createCognitiveTurnLifecycle({
|
|
|
332
340
|
&& existing.supersedes === (observation.supersedes ?? null)
|
|
333
341
|
&& existing.withdraws === (observation.withdraws ?? null)
|
|
334
342
|
&& existing.source.provider === normalizedSource.provider
|
|
343
|
+
&& existing.source.channel_id === normalizedSource.channel_id
|
|
335
344
|
&& existing.source.actor_id === normalizedSource.actor_id
|
|
336
345
|
&& existing.source.context_id === normalizedSource.context_id
|
|
337
346
|
&& existing.source.message_id === normalizedSource.message_id;
|
|
@@ -349,6 +358,8 @@ function createCognitiveTurnLifecycle({
|
|
|
349
358
|
eventId,
|
|
350
359
|
expectedVersion: current.version,
|
|
351
360
|
occurredAt: normalizedOccurredAt,
|
|
361
|
+
receivedAt,
|
|
362
|
+
retentionClass: 'durable',
|
|
352
363
|
source: normalizedSource,
|
|
353
364
|
observations: [observation],
|
|
354
365
|
}, revisionMemoryAccess);
|
|
@@ -462,6 +462,7 @@ function recordChannelIdentity(envelope, env = process.env) {
|
|
|
462
462
|
const groupId = chatId.startsWith('-') ? `telegram-chat-${chatId.slice(1)}` : undefined;
|
|
463
463
|
const displayName = cleanText(meta.user, 120) || actorId;
|
|
464
464
|
const firstSeenAt = trustedTimestamp(meta.ts);
|
|
465
|
+
const receivedAt = trustedTimestamp(meta.received_at) || firstSeenAt;
|
|
465
466
|
const created = [];
|
|
466
467
|
if (createJsonOnce(root, ['actors', `${actorId}.json`], {
|
|
467
468
|
version: 1,
|
|
@@ -517,6 +518,7 @@ function recordChannelIdentity(envelope, env = process.env) {
|
|
|
517
518
|
sourceChannel: groupId ? 'group' : 'direct',
|
|
518
519
|
conversationId: groupId || `telegram-dm-${chatId}`,
|
|
519
520
|
messageId: safeId(meta.message_id),
|
|
521
|
+
receivedAt,
|
|
520
522
|
});
|
|
521
523
|
if (firstSeenAt) recordInteractionActivity(root, agentId, actorId, firstSeenAt);
|
|
522
524
|
const modelContext = renderIdentityContext({
|
|
@@ -9,7 +9,7 @@ const SAFE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u;
|
|
|
9
9
|
const SENSITIVITIES = new Set(['low', 'medium']);
|
|
10
10
|
const INPUT_KEYS = [
|
|
11
11
|
'actorId', 'agentId', 'conversationId', 'cooldownMs', 'messageId', 'occurredAt',
|
|
12
|
-
'sensitivity', 'sourceChannel', 'sourcePortal', 'tenantId', 'topic',
|
|
12
|
+
'receivedAt', 'sensitivity', 'sourceChannel', 'sourcePortal', 'tenantId', 'topic',
|
|
13
13
|
];
|
|
14
14
|
const MAX_COOLDOWN_MS = 90 * 24 * 60 * 60 * 1000;
|
|
15
15
|
|
|
@@ -49,6 +49,7 @@ function normalizePresentation(input) {
|
|
|
49
49
|
conversationId: safeId(input.conversationId),
|
|
50
50
|
messageId: safeId(input.messageId),
|
|
51
51
|
occurredAt: String(input.occurredAt ?? '').trim(),
|
|
52
|
+
receivedAt: String(input.receivedAt ?? '').trim(),
|
|
52
53
|
topic: safeId(input.topic),
|
|
53
54
|
sensitivity: String(input.sensitivity ?? ''),
|
|
54
55
|
cooldownMs: Number(input.cooldownMs),
|
|
@@ -57,11 +58,13 @@ function normalizePresentation(input) {
|
|
|
57
58
|
|| !normalized.sourcePortal || !normalized.sourceChannel || !normalized.conversationId
|
|
58
59
|
|| !normalized.messageId || !normalized.topic || !SENSITIVITIES.has(normalized.sensitivity)
|
|
59
60
|
|| Number.isNaN(Date.parse(normalized.occurredAt))
|
|
61
|
+
|| Number.isNaN(Date.parse(normalized.receivedAt))
|
|
60
62
|
|| !Number.isSafeInteger(normalized.cooldownMs) || normalized.cooldownMs < 1000
|
|
61
63
|
|| normalized.cooldownMs > MAX_COOLDOWN_MS) {
|
|
62
64
|
fail('PERSONALITY_MEMORY_INVALID_INPUT');
|
|
63
65
|
}
|
|
64
66
|
normalized.occurredAt = new Date(normalized.occurredAt).toISOString();
|
|
67
|
+
normalized.receivedAt = new Date(normalized.receivedAt).toISOString();
|
|
65
68
|
return normalized;
|
|
66
69
|
}
|
|
67
70
|
|
|
@@ -138,8 +141,11 @@ function createPersonalityMemoryAdapter({ identityRoot, memoryAdapter } = {}) {
|
|
|
138
141
|
eventId,
|
|
139
142
|
expectedVersion: current.version,
|
|
140
143
|
occurredAt: value.occurredAt,
|
|
144
|
+
receivedAt: value.receivedAt,
|
|
145
|
+
retentionClass: 'relationship',
|
|
141
146
|
source: {
|
|
142
147
|
provider: value.sourcePortal,
|
|
148
|
+
channel_id: value.sourceChannel,
|
|
143
149
|
actor_id: value.actorId,
|
|
144
150
|
context_id: value.conversationId,
|
|
145
151
|
message_id: value.messageId,
|
|
@@ -64,11 +64,12 @@ function prepareCuriosityOpportunity(input = {}) {
|
|
|
64
64
|
const agentId = safeId(input.agentId);
|
|
65
65
|
const actorId = safeId(input.actorId);
|
|
66
66
|
const occurredAt = trustedTimestamp(input.occurredAt);
|
|
67
|
+
const receivedAt = trustedTimestamp(input.receivedAt);
|
|
67
68
|
const sourcePortal = safeId(input.sourcePortal) || 'telegram';
|
|
68
69
|
const sourceChannel = safeId(input.sourceChannel) || 'direct';
|
|
69
70
|
const conversationId = safeId(input.conversationId) || digestId('conversation', [actorId]);
|
|
70
71
|
const cue = curiosityCue(input.text);
|
|
71
|
-
if (!tenantId || !agentId || !actorId || !occurredAt || !cue) return undefined;
|
|
72
|
+
if (!tenantId || !agentId || !actorId || !occurredAt || !receivedAt || !cue) return undefined;
|
|
72
73
|
const messageId = safeId(input.messageId) || digestId('message', [
|
|
73
74
|
sourcePortal, sourceChannel, conversationId, actorId, occurredAt, normalizedText(input.text),
|
|
74
75
|
]);
|
|
@@ -88,6 +89,7 @@ function prepareCuriosityOpportunity(input = {}) {
|
|
|
88
89
|
conversationId,
|
|
89
90
|
messageId,
|
|
90
91
|
occurredAt,
|
|
92
|
+
receivedAt,
|
|
91
93
|
topic: cue.topic,
|
|
92
94
|
sensitivity: cue.sensitivity,
|
|
93
95
|
cooldownMs: COOLDOWN_MS,
|