sentinelayer-cli 0.30.5 → 0.30.7
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/package.json
CHANGED
package/src/commands/session.js
CHANGED
|
@@ -5867,10 +5867,11 @@ export function registerSessionCommand(program) {
|
|
|
5867
5867
|
? buildSessionActionEvents(normalizedSessionId, remoteActions.actions)
|
|
5868
5868
|
: [];
|
|
5869
5869
|
const includeControlEvents = Boolean(options.includeControlEvents);
|
|
5870
|
+
const dedupedEvents = dedupeSessionEvents(events);
|
|
5870
5871
|
const transcriptBaseEvents = includeControlEvents
|
|
5871
|
-
?
|
|
5872
|
-
: filterSessionMaterialEvents(
|
|
5873
|
-
const hiddenControlEventCount =
|
|
5872
|
+
? dedupedEvents
|
|
5873
|
+
: filterSessionMaterialEvents(dedupedEvents);
|
|
5874
|
+
const hiddenControlEventCount = dedupedEvents.length - transcriptBaseEvents.length;
|
|
5874
5875
|
const exportEvents = mergeSessionActionEvents(transcriptBaseEvents, actionEvents);
|
|
5875
5876
|
const stats = computeTranscriptStats({
|
|
5876
5877
|
sessionMeta: sessionPayload,
|
|
@@ -6021,10 +6022,11 @@ export function registerSessionCommand(program) {
|
|
|
6021
6022
|
? buildSessionActionEvents(normalizedSessionId, remoteActions.actions)
|
|
6022
6023
|
: [];
|
|
6023
6024
|
const includeControlEvents = Boolean(options.includeControlEvents);
|
|
6025
|
+
const dedupedEvents = dedupeSessionEvents(events);
|
|
6024
6026
|
const transcriptBaseEvents = includeControlEvents
|
|
6025
|
-
?
|
|
6026
|
-
: filterSessionMaterialEvents(
|
|
6027
|
-
const hiddenControlEventCount =
|
|
6027
|
+
? dedupedEvents
|
|
6028
|
+
: filterSessionMaterialEvents(dedupedEvents);
|
|
6029
|
+
const hiddenControlEventCount = dedupedEvents.length - transcriptBaseEvents.length;
|
|
6028
6030
|
const transcriptEvents = mergeSessionActionEvents(transcriptBaseEvents, actionEvents);
|
|
6029
6031
|
|
|
6030
6032
|
// Pull GitHub/Google avatar + display name from the active auth
|
|
@@ -52,9 +52,61 @@ function stableStringify(value) {
|
|
|
52
52
|
return JSON.stringify(stableJsonValue(value));
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
function messageEventCanUseRelaxedContentKey(eventKind) {
|
|
56
|
+
return [
|
|
57
|
+
"agent_response",
|
|
58
|
+
"human_relay",
|
|
59
|
+
"session_message",
|
|
60
|
+
"session_say",
|
|
61
|
+
].includes(keyString(eventKind));
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function eventDurabilityScore(event = {}) {
|
|
65
|
+
let score = 0;
|
|
66
|
+
if (readSessionEventSequence(event) > 0) score += 2;
|
|
67
|
+
if (sessionEventHasDurableCursor(event)) score += 1;
|
|
68
|
+
return score;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function mergeObjectPreferringPrimary(primaryValue, secondaryValue) {
|
|
72
|
+
if (
|
|
73
|
+
primaryValue &&
|
|
74
|
+
typeof primaryValue === "object" &&
|
|
75
|
+
!Array.isArray(primaryValue) &&
|
|
76
|
+
secondaryValue &&
|
|
77
|
+
typeof secondaryValue === "object" &&
|
|
78
|
+
!Array.isArray(secondaryValue)
|
|
79
|
+
) {
|
|
80
|
+
return { ...secondaryValue, ...primaryValue };
|
|
81
|
+
}
|
|
82
|
+
return primaryValue === undefined ? secondaryValue : primaryValue;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function mergeDuplicateEvent(existingEvent = {}, candidateEvent = {}) {
|
|
86
|
+
const existingScore = eventDurabilityScore(existingEvent);
|
|
87
|
+
const candidateScore = eventDurabilityScore(candidateEvent);
|
|
88
|
+
const candidateIsPrimary = candidateScore > existingScore || (
|
|
89
|
+
candidateScore === existingScore &&
|
|
90
|
+
sessionEventUpgradesExisting(existingEvent, candidateEvent)
|
|
91
|
+
) || (
|
|
92
|
+
candidateScore === existingScore &&
|
|
93
|
+
!sessionEventUpgradesExisting(candidateEvent, existingEvent)
|
|
94
|
+
);
|
|
95
|
+
const primaryEvent = candidateIsPrimary ? candidateEvent : existingEvent;
|
|
96
|
+
const secondaryEvent = candidateIsPrimary ? existingEvent : candidateEvent;
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
...secondaryEvent,
|
|
100
|
+
...primaryEvent,
|
|
101
|
+
agent: mergeObjectPreferringPrimary(primaryEvent.agent, secondaryEvent.agent),
|
|
102
|
+
payload: mergeObjectPreferringPrimary(primaryEvent.payload, secondaryEvent.payload),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
55
106
|
export function sessionEventIdentityKeys(event = {}) {
|
|
56
107
|
if (!event || typeof event !== "object") return [];
|
|
57
108
|
const keys = [];
|
|
109
|
+
const eventKind = keyString(event.event || event.type);
|
|
58
110
|
const id = keyString(event.id);
|
|
59
111
|
if (id) {
|
|
60
112
|
keys.push(`id:${id}`);
|
|
@@ -109,7 +161,7 @@ export function sessionEventIdentityKeys(event = {}) {
|
|
|
109
161
|
if (message) {
|
|
110
162
|
try {
|
|
111
163
|
keys.push(`content:${stableStringify({
|
|
112
|
-
event:
|
|
164
|
+
event: eventKind,
|
|
113
165
|
agent: keyString(event.agent?.id || event.agentId || payload.agentId || payload.authorId),
|
|
114
166
|
payload: {
|
|
115
167
|
channel: keyString(payload.channel),
|
|
@@ -123,6 +175,22 @@ export function sessionEventIdentityKeys(event = {}) {
|
|
|
123
175
|
} catch {
|
|
124
176
|
// Best-effort duplicate suppression only.
|
|
125
177
|
}
|
|
178
|
+
if (messageEventCanUseRelaxedContentKey(eventKind)) {
|
|
179
|
+
try {
|
|
180
|
+
keys.push(`content-relaxed:${stableStringify({
|
|
181
|
+
event: eventKind,
|
|
182
|
+
agent: keyString(event.agent?.id || event.agentId || payload.agentId || payload.authorId),
|
|
183
|
+
payload: {
|
|
184
|
+
channel: keyString(payload.channel),
|
|
185
|
+
message,
|
|
186
|
+
source: keyString(payload.source),
|
|
187
|
+
},
|
|
188
|
+
ts: timestampKey(event.ts, event.timestamp, event.at),
|
|
189
|
+
})}`);
|
|
190
|
+
} catch {
|
|
191
|
+
// Best-effort duplicate suppression only.
|
|
192
|
+
}
|
|
193
|
+
}
|
|
126
194
|
}
|
|
127
195
|
return keys;
|
|
128
196
|
}
|
|
@@ -151,7 +219,7 @@ export function dedupeSessionEvents(events = []) {
|
|
|
151
219
|
const existingIndex = existingIndexes.length > 0 ? Math.min(...existingIndexes) : -1;
|
|
152
220
|
|
|
153
221
|
if (existingIndex >= 0) {
|
|
154
|
-
deduped[existingIndex] = event;
|
|
222
|
+
deduped[existingIndex] = mergeDuplicateEvent(deduped[existingIndex], event);
|
|
155
223
|
for (const key of keys) {
|
|
156
224
|
indexByKey.set(key, existingIndex);
|
|
157
225
|
}
|