@ouro.bot/cli 0.1.0-alpha.807 → 0.1.0-alpha.809
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/changelog.json +16 -0
- package/deploy/unraid/sanctuary.ouro/bundle-meta.json +1 -1
- package/deploy/unraid/sanctuary.xml +1 -1
- package/dist/heart/core.js +156 -188
- package/dist/heart/mailbox/readers/sessions.js +2 -3
- package/dist/heart/session-activity.js +3 -1
- package/dist/heart/session-events.js +167 -55
- package/dist/heart/session-redaction-repair-cli-main.js +31 -0
- package/dist/heart/session-redaction-repair.js +543 -0
- package/dist/heart/session-transcript.js +1 -1
- package/dist/mind/session-transaction.js +180 -31
- package/dist/senses/shared-turn.js +5 -3
- package/npm-shrinkwrap.json +94 -100
- package/package.json +2 -2
|
@@ -121,7 +121,6 @@ function resolveAllSessionPaths(sessionsDir) {
|
|
|
121
121
|
return results;
|
|
122
122
|
}
|
|
123
123
|
/* v8 ignore stop */
|
|
124
|
-
/* v8 ignore start — defensive parsing */
|
|
125
124
|
function readSessionInventory(agentName, options = {}) {
|
|
126
125
|
const bundlesRoot = options.bundlesRoot ?? (0, identity_1.getAgentBundlesRoot)();
|
|
127
126
|
const now = options.now?.() ?? new Date();
|
|
@@ -134,7 +133,7 @@ function readSessionInventory(agentName, options = {}) {
|
|
|
134
133
|
if (friendId === "self" && channel === "inner")
|
|
135
134
|
continue;
|
|
136
135
|
const envelope = (0, shared_1.readSessionEnvelope)(sessionPath);
|
|
137
|
-
const events = envelope?.events ?? [];
|
|
136
|
+
const events = (0, session_events_1.selectEffectiveSessionEvents)(envelope?.events ?? []);
|
|
138
137
|
const chronology = (0, session_events_1.deriveSessionChronology)(events);
|
|
139
138
|
const lastUsage = parseSessionUsage(envelope?.lastUsage);
|
|
140
139
|
const continuity = parseSessionContinuity(envelope?.state);
|
|
@@ -213,7 +212,7 @@ function readSessionTranscript(agentName, friendId, channel, key, options = {})
|
|
|
213
212
|
const envelope = (0, shared_1.readSessionEnvelope)(sessionPath);
|
|
214
213
|
if (!envelope)
|
|
215
214
|
return null;
|
|
216
|
-
const rawMessages = envelope.events;
|
|
215
|
+
const rawMessages = (0, session_events_1.selectEffectiveSessionEvents)(envelope.events);
|
|
217
216
|
const friendsDir = path.join(agentRoot, "friends");
|
|
218
217
|
const friendName = (0, shared_1.resolveFriendName)(friendsDir, friendId);
|
|
219
218
|
const messages = rawMessages;
|
|
@@ -81,7 +81,9 @@ function parseFriendActivity(sessionPath, activeThresholdMs, nowMs) {
|
|
|
81
81
|
}
|
|
82
82
|
const envelope = (0, session_events_1.loadSessionEnvelopeFile)(sessionPath);
|
|
83
83
|
const chronology = envelope ? (0, session_events_1.deriveSessionChronology)(envelope.events) : null;
|
|
84
|
-
const explicit = envelope
|
|
84
|
+
const explicit = envelope && envelope.events.length > 0 && (0, session_events_1.selectEffectiveSessionEvents)(envelope.events).length !== envelope.events.length
|
|
85
|
+
? chronology?.lastInboundAt
|
|
86
|
+
: envelope?.state.lastFriendActivityAt;
|
|
85
87
|
if (typeof explicit === "string") {
|
|
86
88
|
const parsedMs = Date.parse(explicit);
|
|
87
89
|
if (Number.isFinite(parsedMs)) {
|
|
@@ -61,12 +61,15 @@ exports.extractEventText = extractEventText;
|
|
|
61
61
|
exports.deriveSessionChronology = deriveSessionChronology;
|
|
62
62
|
exports.describeCurrentSessionTiming = describeCurrentSessionTiming;
|
|
63
63
|
exports.migrateLegacySessionEnvelope = migrateLegacySessionEnvelope;
|
|
64
|
+
exports.isExactRawSessionRedactionMarker = isExactRawSessionRedactionMarker;
|
|
65
|
+
exports.selectEffectiveSessionEvents = selectEffectiveSessionEvents;
|
|
64
66
|
exports.parseSessionEnvelope = parseSessionEnvelope;
|
|
65
67
|
exports.loadSessionEnvelopeFile = loadSessionEnvelopeFile;
|
|
66
68
|
exports.buildCanonicalSessionEnvelope = buildCanonicalSessionEnvelope;
|
|
67
69
|
exports.appendSyntheticAssistantEvent = appendSyntheticAssistantEvent;
|
|
68
70
|
const fs = __importStar(require("fs"));
|
|
69
71
|
const node_crypto_1 = require("node:crypto");
|
|
72
|
+
const node_util_1 = require("node:util");
|
|
70
73
|
const runtime_1 = require("../nerves/runtime");
|
|
71
74
|
const structured_output_1 = require("./structured-output");
|
|
72
75
|
const APPROVAL_TERMINAL_TEXT = {
|
|
@@ -942,12 +945,15 @@ function projectedSessionEventIds(envelope) {
|
|
|
942
945
|
? envelope.projection.eventIds
|
|
943
946
|
: envelope.events.map((event) => event.id);
|
|
944
947
|
}
|
|
945
|
-
function
|
|
948
|
+
function providerProjectionEvents(envelope) {
|
|
946
949
|
const eventIds = projectedSessionEventIds(envelope);
|
|
947
|
-
const byId = new Map(envelope.events.map((event) => [event.id, event]));
|
|
950
|
+
const byId = new Map(selectEffectiveSessionEvents(envelope.events).map((event) => [event.id, event]));
|
|
948
951
|
return eventIds
|
|
949
952
|
.map((id) => byId.get(id))
|
|
950
|
-
.filter((event) => Boolean(event))
|
|
953
|
+
.filter((event) => Boolean(event));
|
|
954
|
+
}
|
|
955
|
+
function projectProviderMessages(envelope) {
|
|
956
|
+
return providerProjectionEvents(envelope)
|
|
951
957
|
.map((event) => toProviderMessage({
|
|
952
958
|
role: event.role,
|
|
953
959
|
content: event.content,
|
|
@@ -962,11 +968,7 @@ function projectProviderMessages(envelope) {
|
|
|
962
968
|
* System and tool messages are untouched.
|
|
963
969
|
*/
|
|
964
970
|
function annotateMessageTimestamps(envelope, messages, nowMs = Date.now()) {
|
|
965
|
-
const
|
|
966
|
-
const byId = new Map(envelope.events.map((event) => [event.id, event]));
|
|
967
|
-
const events = eventIds
|
|
968
|
-
.map((id) => byId.get(id))
|
|
969
|
-
.filter((event) => Boolean(event));
|
|
971
|
+
const events = providerProjectionEvents(envelope);
|
|
970
972
|
return messages.map((msg, i) => {
|
|
971
973
|
const event = events[i];
|
|
972
974
|
if (!event)
|
|
@@ -1012,6 +1014,7 @@ function extractEventText(event) {
|
|
|
1012
1014
|
return contentText(event.content);
|
|
1013
1015
|
}
|
|
1014
1016
|
function deriveSessionChronology(events) {
|
|
1017
|
+
events = selectEffectiveSessionEvents(events);
|
|
1015
1018
|
let lastInboundAt = null;
|
|
1016
1019
|
let lastOutboundAt = null;
|
|
1017
1020
|
let lastActivityAt = null;
|
|
@@ -1081,6 +1084,139 @@ function migrateLegacySessionEnvelope(raw, options) {
|
|
|
1081
1084
|
state: normalizeContinuityState(legacy.state),
|
|
1082
1085
|
};
|
|
1083
1086
|
}
|
|
1087
|
+
function normalizeSessionEvent(event, index, recordedAt) {
|
|
1088
|
+
const role = normalizeRole(event.role);
|
|
1089
|
+
const time = event.time;
|
|
1090
|
+
const relations = event.relations;
|
|
1091
|
+
const provenance = event.provenance;
|
|
1092
|
+
const content = sanitizeConversationContent(role, normalizeContent(event.content));
|
|
1093
|
+
return {
|
|
1094
|
+
id: typeof event.id === "string" ? event.id : makeEventId(index + 1),
|
|
1095
|
+
sequence: typeof event.sequence === "number" ? event.sequence : index + 1,
|
|
1096
|
+
role,
|
|
1097
|
+
content,
|
|
1098
|
+
name: typeof event.name === "string" ? event.name : null,
|
|
1099
|
+
toolCallId: typeof event.toolCallId === "string" ? event.toolCallId : null,
|
|
1100
|
+
toolCalls: normalizeToolCalls(event.toolCalls),
|
|
1101
|
+
attachments: Array.isArray(event.attachments) ? event.attachments.filter((item) => typeof item === "string") : [],
|
|
1102
|
+
time: {
|
|
1103
|
+
authoredAt: typeof time?.authoredAt === "string" ? time.authoredAt : null,
|
|
1104
|
+
authoredAtSource: typeof time?.authoredAtSource === "string" ? time.authoredAtSource : "unknown",
|
|
1105
|
+
observedAt: typeof time?.observedAt === "string" ? time.observedAt : null,
|
|
1106
|
+
observedAtSource: typeof time?.observedAtSource === "string" ? time.observedAtSource : "unknown",
|
|
1107
|
+
recordedAt: typeof time?.recordedAt === "string" ? time.recordedAt : recordedAt,
|
|
1108
|
+
recordedAtSource: typeof time?.recordedAtSource === "string" ? time.recordedAtSource : "save",
|
|
1109
|
+
},
|
|
1110
|
+
relations: {
|
|
1111
|
+
replyToEventId: typeof relations?.replyToEventId === "string" ? relations.replyToEventId : null,
|
|
1112
|
+
threadRootEventId: typeof relations?.threadRootEventId === "string" ? relations.threadRootEventId : null,
|
|
1113
|
+
references: Array.isArray(relations?.references) ? relations.references.filter((item) => typeof item === "string") : [],
|
|
1114
|
+
toolCallId: typeof relations?.toolCallId === "string" ? relations.toolCallId : null,
|
|
1115
|
+
supersedesEventId: typeof relations?.supersedesEventId === "string" ? relations.supersedesEventId : null,
|
|
1116
|
+
redactsEventId: typeof relations?.redactsEventId === "string" ? relations.redactsEventId : null,
|
|
1117
|
+
},
|
|
1118
|
+
provenance: {
|
|
1119
|
+
captureKind: typeof provenance?.captureKind === "string" ? provenance.captureKind : "live",
|
|
1120
|
+
legacyVersion: typeof provenance?.legacyVersion === "number" ? provenance.legacyVersion : null,
|
|
1121
|
+
sourceMessageIndex: typeof provenance?.sourceMessageIndex === "number" ? provenance.sourceMessageIndex : null,
|
|
1122
|
+
},
|
|
1123
|
+
};
|
|
1124
|
+
}
|
|
1125
|
+
function exactKeys(value, keys) {
|
|
1126
|
+
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
1127
|
+
&& Reflect.ownKeys(value).length === keys.length
|
|
1128
|
+
&& keys.every((key) => Object.prototype.hasOwnProperty.call(value, key));
|
|
1129
|
+
}
|
|
1130
|
+
function nonblank(value) {
|
|
1131
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
1132
|
+
}
|
|
1133
|
+
function exactIsoTime(value) {
|
|
1134
|
+
return typeof value === "string" && Number.isFinite(Date.parse(value)) && new Date(value).toISOString() === value;
|
|
1135
|
+
}
|
|
1136
|
+
function exactRawEvent(value, index) {
|
|
1137
|
+
if (!exactKeys(value, ["id", "sequence", "role", "content", "name", "toolCallId", "toolCalls", "attachments", "time", "relations", "provenance"]))
|
|
1138
|
+
return false;
|
|
1139
|
+
if (!nonblank(value.id) || !Number.isSafeInteger(value.sequence) || Number(value.sequence) <= 0
|
|
1140
|
+
|| typeof value.role !== "string" || !["system", "user", "assistant", "tool"].includes(value.role)
|
|
1141
|
+
|| !(value.name === null || typeof value.name === "string") || !(value.toolCallId === null || typeof value.toolCallId === "string")
|
|
1142
|
+
|| !(value.content === null || typeof value.content === "string" || Array.isArray(value.content))
|
|
1143
|
+
|| !Array.isArray(value.attachments) || !value.attachments.every((item) => typeof item === "string")
|
|
1144
|
+
|| !Array.isArray(value.toolCalls))
|
|
1145
|
+
return false;
|
|
1146
|
+
for (const call of value.toolCalls) {
|
|
1147
|
+
if (!exactKeys(call, ["id", "type", "function"]) || !nonblank(call.id) || call.type !== "function"
|
|
1148
|
+
|| !exactKeys(call.function, ["name", "arguments"]) || !nonblank(call.function.name) || typeof call.function.arguments !== "string")
|
|
1149
|
+
return false;
|
|
1150
|
+
}
|
|
1151
|
+
const time = value.time;
|
|
1152
|
+
if (!exactKeys(time, ["authoredAt", "authoredAtSource", "observedAt", "observedAtSource", "recordedAt", "recordedAtSource"])
|
|
1153
|
+
|| !(time.authoredAt === null || exactIsoTime(time.authoredAt))
|
|
1154
|
+
|| !(time.observedAt === null || exactIsoTime(time.observedAt)) || !exactIsoTime(time.recordedAt))
|
|
1155
|
+
return false;
|
|
1156
|
+
for (const key of ["authoredAtSource", "observedAtSource", "recordedAtSource"]) {
|
|
1157
|
+
if (typeof time[key] !== "string" || !["unknown", "local", "ingest", "migration", "save"].includes(time[key]))
|
|
1158
|
+
return false;
|
|
1159
|
+
}
|
|
1160
|
+
const relations = value.relations;
|
|
1161
|
+
if (!exactKeys(relations, ["replyToEventId", "threadRootEventId", "references", "toolCallId", "supersedesEventId", "redactsEventId"])
|
|
1162
|
+
|| !Array.isArray(relations.references) || !relations.references.every((item) => typeof item === "string"))
|
|
1163
|
+
return false;
|
|
1164
|
+
for (const key of ["replyToEventId", "threadRootEventId", "toolCallId", "supersedesEventId", "redactsEventId"]) {
|
|
1165
|
+
if (relations[key] !== null && typeof relations[key] !== "string")
|
|
1166
|
+
return false;
|
|
1167
|
+
}
|
|
1168
|
+
const provenance = value.provenance;
|
|
1169
|
+
if (!exactKeys(provenance, ["captureKind", "legacyVersion", "sourceMessageIndex"])
|
|
1170
|
+
|| typeof provenance.captureKind !== "string" || !["live", "synthetic", "migration"].includes(provenance.captureKind)
|
|
1171
|
+
|| !(provenance.legacyVersion === null || Number.isSafeInteger(provenance.legacyVersion) && Number(provenance.legacyVersion) > 0)
|
|
1172
|
+
|| !(provenance.sourceMessageIndex === null || Number.isSafeInteger(provenance.sourceMessageIndex) && Number(provenance.sourceMessageIndex) >= 0))
|
|
1173
|
+
return false;
|
|
1174
|
+
return (0, node_util_1.isDeepStrictEqual)(value, normalizeSessionEvent(value, index, time.recordedAt));
|
|
1175
|
+
}
|
|
1176
|
+
function isExactRawSessionRedactionMarker(candidate, rawEvents) {
|
|
1177
|
+
if (!candidate || typeof candidate !== "object" || candidate.role !== "system"
|
|
1178
|
+
|| !exactRawEvent(candidate, 0) || candidate.content !== null || candidate.name !== null || candidate.toolCallId !== null
|
|
1179
|
+
|| candidate.toolCalls.length !== 0 || candidate.attachments.length !== 0
|
|
1180
|
+
|| candidate.time.authoredAt !== null || candidate.time.observedAt !== null
|
|
1181
|
+
|| candidate.time.authoredAtSource !== "migration" || candidate.time.observedAtSource !== "migration" || candidate.time.recordedAtSource !== "migration"
|
|
1182
|
+
|| candidate.provenance.captureKind !== "migration" || candidate.provenance.legacyVersion !== 2 || candidate.provenance.sourceMessageIndex !== null
|
|
1183
|
+
|| candidate.relations.replyToEventId !== null || candidate.relations.threadRootEventId !== null || candidate.relations.references.length !== 0
|
|
1184
|
+
|| candidate.relations.toolCallId !== null || candidate.relations.supersedesEventId !== null || !nonblank(candidate.relations.redactsEventId)
|
|
1185
|
+
|| !Array.isArray(rawEvents))
|
|
1186
|
+
return false;
|
|
1187
|
+
const ids = new Set();
|
|
1188
|
+
let previousSequence = 0;
|
|
1189
|
+
for (const raw of rawEvents) {
|
|
1190
|
+
if (!raw || typeof raw !== "object")
|
|
1191
|
+
return false;
|
|
1192
|
+
const event = raw;
|
|
1193
|
+
if (!nonblank(event.id) || ids.has(event.id) || !Number.isSafeInteger(event.sequence) || Number(event.sequence) <= previousSequence)
|
|
1194
|
+
return false;
|
|
1195
|
+
ids.add(event.id);
|
|
1196
|
+
previousSequence = Number(event.sequence);
|
|
1197
|
+
}
|
|
1198
|
+
const candidateIndex = rawEvents.findIndex((raw) => raw.id === candidate.id);
|
|
1199
|
+
if (candidateIndex < 0 || !(0, node_util_1.isDeepStrictEqual)(rawEvents[candidateIndex], candidate))
|
|
1200
|
+
return false;
|
|
1201
|
+
const targetIndex = rawEvents.findIndex((raw) => raw.id === candidate.relations.redactsEventId);
|
|
1202
|
+
if (targetIndex < 0 || targetIndex >= candidateIndex)
|
|
1203
|
+
return false;
|
|
1204
|
+
const target = rawEvents[targetIndex];
|
|
1205
|
+
if (!exactRawEvent(target, targetIndex) || target.role !== "user" || target.relations.redactsEventId !== null)
|
|
1206
|
+
return false;
|
|
1207
|
+
const attempts = rawEvents.map((raw) => raw.relations?.redactsEventId);
|
|
1208
|
+
return attempts.filter((id) => id === target.id).length === 1 && !attempts.includes(candidate.id);
|
|
1209
|
+
}
|
|
1210
|
+
function selectEffectiveSessionEvents(events) {
|
|
1211
|
+
const hidden = new Set();
|
|
1212
|
+
for (const event of events) {
|
|
1213
|
+
if (isExactRawSessionRedactionMarker(event, events)) {
|
|
1214
|
+
hidden.add(event.id);
|
|
1215
|
+
hidden.add(event.relations.redactsEventId);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
return events.filter((event) => !hidden.has(event.id));
|
|
1219
|
+
}
|
|
1084
1220
|
function parseSessionEnvelope(raw, options = {}) {
|
|
1085
1221
|
const recordedAt = options.recordedAt ?? new Date().toISOString();
|
|
1086
1222
|
const fileMtimeAt = options.fileMtimeAt ?? null;
|
|
@@ -1093,46 +1229,24 @@ function parseSessionEnvelope(raw, options = {}) {
|
|
|
1093
1229
|
if (record.version !== 2 || !Array.isArray(record.events) || !record.projection || typeof record.projection !== "object") {
|
|
1094
1230
|
return null;
|
|
1095
1231
|
}
|
|
1232
|
+
const validMarkers = new Set(record.events.filter((event) => isExactRawSessionRedactionMarker(event, record.events)));
|
|
1233
|
+
let invalidMarkers = 0;
|
|
1096
1234
|
const rawEvents = record.events
|
|
1097
1235
|
.filter((event) => event != null && typeof event === "object")
|
|
1098
1236
|
.map((event, index) => {
|
|
1099
|
-
const
|
|
1100
|
-
const
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
sequence: typeof event.sequence === "number" ? event.sequence : index + 1,
|
|
1107
|
-
role,
|
|
1108
|
-
content,
|
|
1109
|
-
name: typeof event.name === "string" ? event.name : null,
|
|
1110
|
-
toolCallId: typeof event.toolCallId === "string" ? event.toolCallId : null,
|
|
1111
|
-
toolCalls: normalizeToolCalls(event.toolCalls),
|
|
1112
|
-
attachments: Array.isArray(event.attachments) ? event.attachments.filter((item) => typeof item === "string") : [],
|
|
1113
|
-
time: {
|
|
1114
|
-
authoredAt: typeof time?.authoredAt === "string" ? time.authoredAt : null,
|
|
1115
|
-
authoredAtSource: typeof time?.authoredAtSource === "string" ? time.authoredAtSource : "unknown",
|
|
1116
|
-
observedAt: typeof time?.observedAt === "string" ? time.observedAt : null,
|
|
1117
|
-
observedAtSource: typeof time?.observedAtSource === "string" ? time.observedAtSource : "unknown",
|
|
1118
|
-
recordedAt: typeof time?.recordedAt === "string" ? time.recordedAt : recordedAt,
|
|
1119
|
-
recordedAtSource: typeof time?.recordedAtSource === "string" ? time.recordedAtSource : "save",
|
|
1120
|
-
},
|
|
1121
|
-
relations: {
|
|
1122
|
-
replyToEventId: typeof relations?.replyToEventId === "string" ? relations.replyToEventId : null,
|
|
1123
|
-
threadRootEventId: typeof relations?.threadRootEventId === "string" ? relations.threadRootEventId : null,
|
|
1124
|
-
references: Array.isArray(relations?.references) ? relations.references.filter((item) => typeof item === "string") : [],
|
|
1125
|
-
toolCallId: typeof relations?.toolCallId === "string" ? relations.toolCallId : null,
|
|
1126
|
-
supersedesEventId: typeof relations?.supersedesEventId === "string" ? relations.supersedesEventId : null,
|
|
1127
|
-
redactsEventId: typeof relations?.redactsEventId === "string" ? relations.redactsEventId : null,
|
|
1128
|
-
},
|
|
1129
|
-
provenance: {
|
|
1130
|
-
captureKind: typeof provenance?.captureKind === "string" ? provenance.captureKind : "live",
|
|
1131
|
-
legacyVersion: typeof provenance?.legacyVersion === "number" ? provenance.legacyVersion : null,
|
|
1132
|
-
sourceMessageIndex: typeof provenance?.sourceMessageIndex === "number" ? provenance.sourceMessageIndex : null,
|
|
1133
|
-
},
|
|
1134
|
-
};
|
|
1237
|
+
const normalized = normalizeSessionEvent(event, index, recordedAt);
|
|
1238
|
+
const attempted = event.relations?.redactsEventId;
|
|
1239
|
+
if (attempted !== undefined && attempted !== null && !validMarkers.has(event)) {
|
|
1240
|
+
normalized.relations.redactsEventId = null;
|
|
1241
|
+
invalidMarkers++;
|
|
1242
|
+
}
|
|
1243
|
+
return normalized;
|
|
1135
1244
|
});
|
|
1245
|
+
if (invalidMarkers > 0)
|
|
1246
|
+
(0, runtime_1.emitNervesEvent)({
|
|
1247
|
+
level: "warn", component: "heart", event: "session.redaction_marker_invalid",
|
|
1248
|
+
message: "invalid raw redaction authority ignored", meta: { count: invalidMarkers },
|
|
1249
|
+
});
|
|
1136
1250
|
// Self-heal duplicate event ids that may have been written by concurrent
|
|
1137
1251
|
// writers in older harness versions. Last-occurrence-wins by id (later
|
|
1138
1252
|
// entries in the persisted file are the more recent state for that id).
|
|
@@ -1151,9 +1265,7 @@ function parseSessionEnvelope(raw, options = {}) {
|
|
|
1151
1265
|
inputTokens: typeof projection.inputTokens === "number" ? projection.inputTokens : null,
|
|
1152
1266
|
projectedAt: typeof projection.projectedAt === "string" ? projection.projectedAt : null,
|
|
1153
1267
|
},
|
|
1154
|
-
structuredOutputs:
|
|
1155
|
-
? (0, structured_output_1.extractStructuredOutputsFromEvents)(events, { emitTelemetry: false })
|
|
1156
|
-
: (0, structured_output_1.normalizeStructuredOutputs)(record.structuredOutputs),
|
|
1268
|
+
structuredOutputs: (0, structured_output_1.extractStructuredOutputsFromEvents)(selectEffectiveSessionEvents(events), { emitTelemetry: false }),
|
|
1157
1269
|
lastUsage: normalizeUsage(record.lastUsage),
|
|
1158
1270
|
state: normalizeContinuityState(record.state),
|
|
1159
1271
|
approvalSuspensions: normalizeApprovalSuspensions(record.approvalSuspensions),
|
|
@@ -1228,9 +1340,7 @@ function buildCanonicalSessionEnvelope(options) {
|
|
|
1228
1340
|
const previousMessages = options.previousMessages;
|
|
1229
1341
|
const currentMessages = options.currentMessages;
|
|
1230
1342
|
const trimmedMessages = options.trimmedMessages;
|
|
1231
|
-
const previousProjectionIds = existing
|
|
1232
|
-
? [...existing.projection.eventIds]
|
|
1233
|
-
: existing?.events.map((event) => event.id) ?? [];
|
|
1343
|
+
const previousProjectionIds = existing ? providerProjectionEvents(existing).map((event) => event.id) : [];
|
|
1234
1344
|
// Compare only non-system messages to find the common prefix.
|
|
1235
1345
|
// System messages change every turn (live world-state in system prompt)
|
|
1236
1346
|
// and must not defeat prefix matching of the actual conversation.
|
|
@@ -1278,21 +1388,23 @@ function buildCanonicalSessionEnvelope(options) {
|
|
|
1278
1388
|
// Prune events: only keep events whose IDs are in the projection.
|
|
1279
1389
|
// Events not in projection are returned as evicted for archiving.
|
|
1280
1390
|
const projectionIdSet = new Set(projectionEventIds);
|
|
1281
|
-
const
|
|
1282
|
-
const
|
|
1391
|
+
const effectiveIds = new Set(selectEffectiveSessionEvents(events).map((event) => event.id));
|
|
1392
|
+
const keep = (event) => projectionIdSet.has(event.id) || !effectiveIds.has(event.id);
|
|
1393
|
+
const prunedEvents = events.filter(keep);
|
|
1394
|
+
const evictedEvents = events.filter((event) => !keep(event));
|
|
1283
1395
|
return {
|
|
1284
1396
|
envelope: {
|
|
1285
1397
|
version: 2,
|
|
1286
1398
|
events: prunedEvents,
|
|
1287
1399
|
projection: {
|
|
1288
|
-
eventIds: projectionEventIds,
|
|
1400
|
+
eventIds: projectionEventIds.filter((id) => effectiveIds.has(id)),
|
|
1289
1401
|
trimmed: projectionEventIds.length < currentEventIds.length,
|
|
1290
1402
|
maxTokens: options.projectionBasis.maxTokens,
|
|
1291
1403
|
contextMargin: options.projectionBasis.contextMargin,
|
|
1292
1404
|
inputTokens: options.projectionBasis.inputTokens,
|
|
1293
1405
|
projectedAt: options.recordedAt,
|
|
1294
1406
|
},
|
|
1295
|
-
structuredOutputs: (0, structured_output_1.extractStructuredOutputsFromEvents)(prunedEvents),
|
|
1407
|
+
structuredOutputs: (0, structured_output_1.extractStructuredOutputsFromEvents)(selectEffectiveSessionEvents(prunedEvents)),
|
|
1296
1408
|
lastUsage: normalizeUsage(options.lastUsage),
|
|
1297
1409
|
state: normalizeContinuityState(options.state),
|
|
1298
1410
|
approvalSuspensions: structuredClone(options.existing?.approvalSuspensions ?? []),
|
|
@@ -1309,7 +1421,7 @@ function appendSyntheticAssistantEvent(envelope, content, recordedAt) {
|
|
|
1309
1421
|
return {
|
|
1310
1422
|
...envelope,
|
|
1311
1423
|
events: [...envelope.events, event],
|
|
1312
|
-
structuredOutputs: (0, structured_output_1.extractStructuredOutputsFromEvents)([...envelope.events, event]),
|
|
1424
|
+
structuredOutputs: (0, structured_output_1.extractStructuredOutputsFromEvents)(selectEffectiveSessionEvents([...envelope.events, event])),
|
|
1313
1425
|
projection: {
|
|
1314
1426
|
...envelope.projection,
|
|
1315
1427
|
eventIds: [...envelope.projection.eventIds, event.id],
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const runtime_1 = require("../nerves/runtime");
|
|
4
|
+
const session_redaction_repair_1 = require("./session-redaction-repair");
|
|
5
|
+
// Deliberately a direct packaged entrypoint, never public CLI/model routing.
|
|
6
|
+
async function main() {
|
|
7
|
+
const args = process.argv.slice(2);
|
|
8
|
+
(0, runtime_1.emitNervesEvent)({ component: "heart", event: "heart.session_redaction_repair_cli", message: "private fixed repair entrypoint invoked", meta: { argumentCount: args.length } });
|
|
9
|
+
try {
|
|
10
|
+
let result;
|
|
11
|
+
if (args.length === 7 && args[0] === "inspect" && args[1] === "--agent" && args[3] === "--session" && args[5] === "--artifacts-dir") {
|
|
12
|
+
result = await (0, session_redaction_repair_1.inspectA003SessionRepair)({ agent: args[2], sessionPath: args[4], artifactsDir: args[6] });
|
|
13
|
+
}
|
|
14
|
+
else if (args.length === 4 && args[0] === "apply" && args[1] === "--manifest-sha256") {
|
|
15
|
+
result = await (0, session_redaction_repair_1.applyA003SessionRepair)({ manifestSha256: args[2], manifestPath: args[3] });
|
|
16
|
+
}
|
|
17
|
+
else if (args.length === 5 && args[0] === "rollback" && args[1] === "--manifest-sha256") {
|
|
18
|
+
result = await (0, session_redaction_repair_1.rollbackA003SessionRepair)({ manifestSha256: args[2], manifestPath: args[3], preimagePath: args[4] });
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
throw new Error("expected fixed inspect, apply, or rollback arguments");
|
|
22
|
+
}
|
|
23
|
+
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
24
|
+
process.exitCode = result.status === "indeterminate" || result.status === "not_applied" ? 1 : 0;
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
process.stdout.write(`${JSON.stringify({ status: "refused", error: (error instanceof Error ? error.message : String(error)).slice(0, 512) })}\n`);
|
|
28
|
+
process.exitCode = 2;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
void main();
|