@ouro.bot/cli 0.1.0-alpha.611 → 0.1.0-alpha.612
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 +10 -0
- package/dist/arc/cares.js +7 -3
- package/dist/arc/episodes.js +4 -3
- package/dist/arc/intentions.js +2 -1
- package/dist/arc/obligations.js +18 -6
- package/dist/arc/packets.js +9 -8
- package/dist/heart/awaiting/await-runtime-state.js +4 -1
- package/dist/heart/bridges/store.js +14 -2
- package/dist/heart/daemon/daemon.js +47 -0
- package/dist/heart/daemon/process-manager.js +13 -0
- package/dist/heart/daemon/sense-manager.js +12 -0
- package/dist/heart/mailbox/readers/runtime-readers.js +107 -2
- package/dist/heart/mailbox/readers/sessions.js +2 -2
- package/dist/heart/session-events.js +73 -66
- package/dist/heart/session-transcript.js +6 -116
- package/dist/mailbox-ui/assets/{index-CtUWEo-S.js → index-9-AxCxuB.js} +3 -3
- package/dist/mailbox-ui/assets/index-CWzt267f.css +1 -0
- package/dist/mailbox-ui/index.html +2 -2
- package/dist/mind/diary.js +6 -1
- package/dist/mind/friends/store-file.js +9 -1
- package/dist/mind/journal-index.js +2 -1
- package/dist/mind/pending.js +2 -1
- package/dist/mind/prompt.js +6 -5
- package/dist/repertoire/coding/context-pack.js +3 -2
- package/dist/repertoire/coding/manager.js +6 -2
- package/dist/repertoire/tools-awaiting.js +11 -6
- package/dist/repertoire/tools-base.js +2 -0
- package/dist/repertoire/tools-bridge.js +0 -1
- package/dist/repertoire/tools-record.js +463 -0
- package/dist/repertoire/tools-runtime.js +87 -0
- package/dist/repertoire/tools-session.js +9 -37
- package/dist/senses/bluebubbles/index.js +1 -1
- package/package.json +1 -1
- package/dist/mailbox-ui/assets/index-BPr5vNuM.css +0 -1
|
@@ -33,6 +33,11 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.EVENT_CONTENT_MAX_CHARS = void 0;
|
|
37
|
+
exports.truncateLargeEventContent = truncateLargeEventContent;
|
|
38
|
+
exports.capStructuredRecordString = capStructuredRecordString;
|
|
39
|
+
exports.capStructuredRecordStringArray = capStructuredRecordStringArray;
|
|
40
|
+
exports.capStructuredRecordStringLeaves = capStructuredRecordStringLeaves;
|
|
36
41
|
exports.normalizeContinuityState = normalizeContinuityState;
|
|
37
42
|
exports.validateSessionMessages = validateSessionMessages;
|
|
38
43
|
exports.detectDuplicateToolCallIds = detectDuplicateToolCallIds;
|
|
@@ -52,11 +57,51 @@ exports.migrateLegacySessionEnvelope = migrateLegacySessionEnvelope;
|
|
|
52
57
|
exports.parseSessionEnvelope = parseSessionEnvelope;
|
|
53
58
|
exports.loadSessionEnvelopeFile = loadSessionEnvelopeFile;
|
|
54
59
|
exports.buildCanonicalSessionEnvelope = buildCanonicalSessionEnvelope;
|
|
55
|
-
exports.loadFullEventHistory = loadFullEventHistory;
|
|
56
60
|
exports.appendEvictedToArchive = appendEvictedToArchive;
|
|
57
61
|
exports.appendSyntheticAssistantEvent = appendSyntheticAssistantEvent;
|
|
58
62
|
const fs = __importStar(require("fs"));
|
|
59
63
|
const runtime_1 = require("../nerves/runtime");
|
|
64
|
+
let archiveDisabledEmitted = false;
|
|
65
|
+
exports.EVENT_CONTENT_MAX_CHARS = 256 * 1024;
|
|
66
|
+
function truncateLargeEventContent(content, maxChars) {
|
|
67
|
+
if (typeof content !== "string") {
|
|
68
|
+
return { content, truncated: false, originalLength: 0 };
|
|
69
|
+
}
|
|
70
|
+
if (content.length <= maxChars) {
|
|
71
|
+
return { content, truncated: false, originalLength: content.length };
|
|
72
|
+
}
|
|
73
|
+
const marker = `[truncated — event content exceeded ${maxChars} chars; original length ${content.length} chars]`;
|
|
74
|
+
const remainingBudget = Math.max(0, maxChars - marker.length);
|
|
75
|
+
const headLength = Math.ceil(remainingBudget * 0.75);
|
|
76
|
+
const tailLength = Math.max(0, remainingBudget - headLength);
|
|
77
|
+
return {
|
|
78
|
+
content: `${content.slice(0, headLength)}${marker}${tailLength > 0 ? content.slice(-tailLength) : ""}`,
|
|
79
|
+
truncated: true,
|
|
80
|
+
originalLength: content.length,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
function capStructuredRecordString(value) {
|
|
84
|
+
return truncateLargeEventContent(value, exports.EVENT_CONTENT_MAX_CHARS).content;
|
|
85
|
+
}
|
|
86
|
+
function capStructuredRecordStringArray(values) {
|
|
87
|
+
return values.map((value) => capStructuredRecordString(value));
|
|
88
|
+
}
|
|
89
|
+
function capStructuredRecordStringLeaves(value) {
|
|
90
|
+
if (typeof value === "string") {
|
|
91
|
+
return capStructuredRecordString(value);
|
|
92
|
+
}
|
|
93
|
+
if (Array.isArray(value)) {
|
|
94
|
+
return value.map((item) => capStructuredRecordStringLeaves(item));
|
|
95
|
+
}
|
|
96
|
+
if (!value || typeof value !== "object") {
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
const capped = {};
|
|
100
|
+
for (const [key, child] of Object.entries(value)) {
|
|
101
|
+
capped[key] = capStructuredRecordStringLeaves(child);
|
|
102
|
+
}
|
|
103
|
+
return capped;
|
|
104
|
+
}
|
|
60
105
|
function formatElapsed(ms) {
|
|
61
106
|
const minutes = Math.max(0, Math.floor(ms / 60000));
|
|
62
107
|
if (minutes < 60)
|
|
@@ -684,11 +729,12 @@ function createEventTime(role, recordedAt, captureKind, ingressAt) {
|
|
|
684
729
|
function buildEventFromMessage(message, sequence, recordedAt, captureKind, sourceMessageIndex, legacyVersion, ingressAt) {
|
|
685
730
|
const normalized = normalizeMessage(message);
|
|
686
731
|
const role = normalized.role;
|
|
732
|
+
const cappedContent = truncateLargeEventContent(normalized.content, exports.EVENT_CONTENT_MAX_CHARS).content;
|
|
687
733
|
return {
|
|
688
734
|
id: makeEventId(sequence),
|
|
689
735
|
sequence,
|
|
690
736
|
role,
|
|
691
|
-
content:
|
|
737
|
+
content: cappedContent,
|
|
692
738
|
name: normalized.name,
|
|
693
739
|
toolCallId: role === "tool" ? normalized.toolCallId : null,
|
|
694
740
|
toolCalls: role === "assistant" ? normalized.toolCalls : [],
|
|
@@ -969,14 +1015,20 @@ function findCommonPrefixLength(a, b) {
|
|
|
969
1015
|
function selectProjectedEventIds(currentMessages, currentEventIds, trimmedMessages) {
|
|
970
1016
|
if (trimmedMessages.length === 0)
|
|
971
1017
|
return [];
|
|
972
|
-
const trimmedFingerprints = trimmedMessages.map(messageFingerprint);
|
|
973
1018
|
const result = [];
|
|
974
1019
|
let needle = 0;
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
1020
|
+
let trimmedFingerprint = null;
|
|
1021
|
+
for (let i = 0; i < currentMessages.length && needle < trimmedMessages.length; i++) {
|
|
1022
|
+
const currentMessage = currentMessages[i];
|
|
1023
|
+
const trimmedMessage = trimmedMessages[needle];
|
|
1024
|
+
if (currentMessage !== trimmedMessage) {
|
|
1025
|
+
trimmedFingerprint ??= messageFingerprint(trimmedMessage);
|
|
1026
|
+
if (messageFingerprint(currentMessage) !== trimmedFingerprint)
|
|
1027
|
+
continue;
|
|
1028
|
+
}
|
|
978
1029
|
result.push(currentEventIds[i]);
|
|
979
1030
|
needle++;
|
|
1031
|
+
trimmedFingerprint = null;
|
|
980
1032
|
}
|
|
981
1033
|
return result;
|
|
982
1034
|
}
|
|
@@ -1057,75 +1109,30 @@ function buildCanonicalSessionEnvelope(options) {
|
|
|
1057
1109
|
evictedEvents,
|
|
1058
1110
|
};
|
|
1059
1111
|
}
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
* Corrupted archive lines are silently skipped.
|
|
1064
|
-
*/
|
|
1065
|
-
function loadFullEventHistory(sessPath) {
|
|
1066
|
-
const envelope = loadSessionEnvelopeFile(sessPath);
|
|
1067
|
-
if (!envelope)
|
|
1068
|
-
return [];
|
|
1069
|
-
const envelopeEvents = envelope.events;
|
|
1070
|
-
const archivePath = sessPath.replace(/\.json$/, ".archive.ndjson");
|
|
1071
|
-
let archiveEvents = [];
|
|
1072
|
-
try {
|
|
1073
|
-
const raw = fs.readFileSync(archivePath, "utf-8");
|
|
1074
|
-
const lines = raw.split("\n");
|
|
1075
|
-
for (const line of lines) {
|
|
1076
|
-
const trimmed = line.trim();
|
|
1077
|
-
if (trimmed.length === 0)
|
|
1078
|
-
continue;
|
|
1079
|
-
try {
|
|
1080
|
-
const event = JSON.parse(trimmed);
|
|
1081
|
-
if (event && typeof event.id === "string" && typeof event.sequence === "number") {
|
|
1082
|
-
archiveEvents.push(event);
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
catch {
|
|
1086
|
-
// Skip corrupted lines
|
|
1087
|
-
}
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
catch {
|
|
1091
|
-
// Archive file doesn't exist or can't be read -- that's fine
|
|
1092
|
-
}
|
|
1093
|
-
// Merge, deduplicate by id, sort by sequence. The live envelope is the
|
|
1094
|
-
// current projection, so it wins if an older archive line has a colliding id.
|
|
1095
|
-
const mergedById = new Map();
|
|
1096
|
-
for (const event of archiveEvents)
|
|
1097
|
-
mergedById.set(event.id, event);
|
|
1098
|
-
for (const event of envelopeEvents)
|
|
1099
|
-
mergedById.set(event.id, event);
|
|
1100
|
-
const merged = [...mergedById.values()];
|
|
1101
|
-
merged.sort((a, b) => a.sequence - b.sequence);
|
|
1102
|
-
return merged;
|
|
1112
|
+
function agentFromSessionPath(sessPath) {
|
|
1113
|
+
const match = sessPath.match(/(?:^|[/\\])AgentBundles[/\\]([^/\\]+)\.ouro(?:[/\\]|$)/);
|
|
1114
|
+
return match?.[1] ?? "unknown";
|
|
1103
1115
|
}
|
|
1104
1116
|
/**
|
|
1105
|
-
*
|
|
1106
|
-
*
|
|
1107
|
-
*
|
|
1108
|
-
* Failures are logged and swallowed -- archive write must never crash the persist path.
|
|
1117
|
+
* Archive writes are intentionally disabled. The session envelope remains the
|
|
1118
|
+
* bounded working-memory record; evicted events are no longer persisted to an
|
|
1119
|
+
* unbounded sidecar.
|
|
1109
1120
|
*/
|
|
1110
1121
|
function appendEvictedToArchive(sessPath, evictedEvents) {
|
|
1111
1122
|
if (evictedEvents.length === 0)
|
|
1112
1123
|
return;
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
const ndjson = evictedEvents.map((event) => JSON.stringify(event)).join("\n") + "\n";
|
|
1116
|
-
fs.appendFileSync(archivePath, ndjson);
|
|
1117
|
-
}
|
|
1118
|
-
catch (err) {
|
|
1124
|
+
if (!archiveDisabledEmitted) {
|
|
1125
|
+
archiveDisabledEmitted = true;
|
|
1119
1126
|
(0, runtime_1.emitNervesEvent)({
|
|
1120
|
-
level: "warn",
|
|
1121
1127
|
component: "heart",
|
|
1122
|
-
event: "heart.
|
|
1123
|
-
message: "
|
|
1128
|
+
event: "heart.session_archive_disabled",
|
|
1129
|
+
message: "session archive append disabled",
|
|
1124
1130
|
meta: {
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1131
|
+
type: "session_archive_disabled",
|
|
1132
|
+
agent: agentFromSessionPath(sessPath),
|
|
1133
|
+
sessionPath: sessPath,
|
|
1134
|
+
evictedCount: evictedEvents.length,
|
|
1135
|
+
ts: new Date().toISOString(),
|
|
1129
1136
|
},
|
|
1130
1137
|
});
|
|
1131
1138
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.summarizeSessionTail = summarizeSessionTail;
|
|
4
|
-
exports.searchSessionTranscript = searchSessionTranscript;
|
|
5
4
|
const runtime_1 = require("../nerves/runtime");
|
|
6
5
|
const session_events_1 = require("./session-events");
|
|
7
6
|
function shouldIncludeToolMessages(friendId, channel) {
|
|
@@ -73,11 +72,9 @@ function clip(text, limit = 160) {
|
|
|
73
72
|
}
|
|
74
73
|
function buildSnapshot(summary, tailMessages) {
|
|
75
74
|
const lines = [`recent focus: ${clip(summary, 240)}`];
|
|
76
|
-
const latestUser = [...tailMessages].reverse().find((message) => message.role === "user")
|
|
75
|
+
const latestUser = [...tailMessages].reverse().find((message) => message.role === "user").content;
|
|
77
76
|
const latestAssistant = [...tailMessages].reverse().find((message) => message.role === "assistant")?.content;
|
|
78
|
-
|
|
79
|
-
lines.push(`latest user: ${clip(latestUser)}`);
|
|
80
|
-
}
|
|
77
|
+
lines.push(`latest user: ${clip(latestUser)}`);
|
|
81
78
|
if (latestAssistant) {
|
|
82
79
|
lines.push(`latest assistant: ${clip(latestAssistant)}`);
|
|
83
80
|
}
|
|
@@ -89,67 +86,11 @@ function selectSessionTailMessages(messages, messageCount) {
|
|
|
89
86
|
const selectedIds = new Set(tail.map((message) => message.id));
|
|
90
87
|
const latestUser = [...messages].reverse().find((message) => message.role === "user");
|
|
91
88
|
const latestAssistant = [...messages].reverse().find((message) => message.role === "assistant");
|
|
92
|
-
|
|
93
|
-
selectedIds.add(latestUser.id);
|
|
89
|
+
selectedIds.add(latestUser.id);
|
|
94
90
|
if (latestAssistant)
|
|
95
91
|
selectedIds.add(latestAssistant.id);
|
|
96
92
|
return messages.filter((message) => selectedIds.has(message.id));
|
|
97
93
|
}
|
|
98
|
-
function buildSearchSnapshot(query, messages, includeLatestTurn = true) {
|
|
99
|
-
const lines = [`history query: "${clip(query, 120)}"`];
|
|
100
|
-
if (!includeLatestTurn) {
|
|
101
|
-
return lines.join("\n");
|
|
102
|
-
}
|
|
103
|
-
const latestUser = [...messages].reverse().find((message) => message.role === "user")?.content;
|
|
104
|
-
const latestAssistant = [...messages].reverse().find((message) => message.role === "assistant")?.content;
|
|
105
|
-
if (latestUser) {
|
|
106
|
-
lines.push(`latest user: ${clip(latestUser)}`);
|
|
107
|
-
}
|
|
108
|
-
if (latestAssistant) {
|
|
109
|
-
lines.push(`latest assistant: ${clip(latestAssistant)}`);
|
|
110
|
-
}
|
|
111
|
-
return lines.join("\n");
|
|
112
|
-
}
|
|
113
|
-
function buildSearchExcerpts(messages, query, maxMatches) {
|
|
114
|
-
const normalizedQuery = query.trim().toLowerCase();
|
|
115
|
-
if (!normalizedQuery)
|
|
116
|
-
return [];
|
|
117
|
-
const candidates = [];
|
|
118
|
-
let lastMatchIndex = -2;
|
|
119
|
-
for (let i = 0; i < messages.length; i++) {
|
|
120
|
-
if (!messages[i].content.toLowerCase().includes(normalizedQuery))
|
|
121
|
-
continue;
|
|
122
|
-
if (i <= lastMatchIndex + 1)
|
|
123
|
-
continue;
|
|
124
|
-
lastMatchIndex = i;
|
|
125
|
-
const start = Math.max(0, i - 1);
|
|
126
|
-
const end = Math.min(messages.length, i + 2);
|
|
127
|
-
const excerpt = messages
|
|
128
|
-
.slice(start, end)
|
|
129
|
-
.map((message) => `[${message.timestamp} | ${message.role} | ${message.id}] ${clip(message.content, 200)}`)
|
|
130
|
-
.join("\n");
|
|
131
|
-
const signature = messages
|
|
132
|
-
.slice(start, end)
|
|
133
|
-
.map((message) => `[${message.role}] ${clip(message.content, 200)}`)
|
|
134
|
-
.join("\n");
|
|
135
|
-
const score = messages
|
|
136
|
-
.slice(start, end)
|
|
137
|
-
.filter((message) => message.content.toLowerCase().includes(normalizedQuery))
|
|
138
|
-
.length;
|
|
139
|
-
candidates.push({ excerpt, signature, score, index: i });
|
|
140
|
-
}
|
|
141
|
-
const seen = new Set();
|
|
142
|
-
return candidates
|
|
143
|
-
.sort((a, b) => b.score - a.score || a.index - b.index)
|
|
144
|
-
.filter((candidate) => {
|
|
145
|
-
if (seen.has(candidate.signature))
|
|
146
|
-
return false;
|
|
147
|
-
seen.add(candidate.signature);
|
|
148
|
-
return true;
|
|
149
|
-
})
|
|
150
|
-
.slice(0, maxMatches)
|
|
151
|
-
.map((candidate) => candidate.excerpt);
|
|
152
|
-
}
|
|
153
94
|
async function summarizeSessionTail(options) {
|
|
154
95
|
(0, runtime_1.emitNervesEvent)({
|
|
155
96
|
component: "daemon",
|
|
@@ -171,16 +112,11 @@ async function summarizeSessionTail(options) {
|
|
|
171
112
|
key: options.key,
|
|
172
113
|
includeToolMessages: shouldIncludeToolMessages(options.friendId, options.channel),
|
|
173
114
|
};
|
|
174
|
-
|
|
175
|
-
if (
|
|
176
|
-
|
|
177
|
-
if (fullHistoryMessages.length > 0)
|
|
178
|
-
visibleMessages = fullHistoryMessages;
|
|
115
|
+
const visibleMessages = normalizeSessionMessages(envelope.events, transcriptContext);
|
|
116
|
+
if (!visibleMessages.some((message) => message.role === "user")) {
|
|
117
|
+
return { kind: "empty", reason: "envelope_trimmed" };
|
|
179
118
|
}
|
|
180
119
|
const tailMessages = selectSessionTailMessages(visibleMessages, options.messageCount);
|
|
181
|
-
if (tailMessages.length === 0) {
|
|
182
|
-
return { kind: "empty" };
|
|
183
|
-
}
|
|
184
120
|
const transcript = tailMessages
|
|
185
121
|
.map((message) => `[${message.timestamp} | ${message.role} | ${message.id}] ${message.content}`)
|
|
186
122
|
.join("\n");
|
|
@@ -195,49 +131,3 @@ async function summarizeSessionTail(options) {
|
|
|
195
131
|
tailMessages,
|
|
196
132
|
};
|
|
197
133
|
}
|
|
198
|
-
async function searchSessionTranscript(options) {
|
|
199
|
-
(0, runtime_1.emitNervesEvent)({
|
|
200
|
-
component: "daemon",
|
|
201
|
-
event: "daemon.session_search",
|
|
202
|
-
message: "searching session transcript",
|
|
203
|
-
meta: {
|
|
204
|
-
friendId: options.friendId,
|
|
205
|
-
channel: options.channel,
|
|
206
|
-
key: options.key,
|
|
207
|
-
query: options.query,
|
|
208
|
-
maxMatches: options.maxMatches ?? 5,
|
|
209
|
-
},
|
|
210
|
-
});
|
|
211
|
-
// Use full event history (envelope + archive) for search to find older messages
|
|
212
|
-
const allEvents = (0, session_events_1.loadFullEventHistory)(options.sessionPath);
|
|
213
|
-
if (allEvents.length === 0) {
|
|
214
|
-
const envelope = (0, session_events_1.loadSessionEnvelopeFile)(options.sessionPath);
|
|
215
|
-
if (!envelope)
|
|
216
|
-
return { kind: "missing" };
|
|
217
|
-
return { kind: "empty" };
|
|
218
|
-
}
|
|
219
|
-
const messages = normalizeSessionMessages(allEvents, {
|
|
220
|
-
friendId: options.friendId,
|
|
221
|
-
channel: options.channel,
|
|
222
|
-
key: options.key,
|
|
223
|
-
includeToolMessages: shouldIncludeToolMessages(options.friendId, options.channel),
|
|
224
|
-
});
|
|
225
|
-
if (messages.length === 0) {
|
|
226
|
-
return { kind: "empty" };
|
|
227
|
-
}
|
|
228
|
-
const query = options.query.trim();
|
|
229
|
-
const matches = buildSearchExcerpts(messages, query, options.maxMatches ?? 5);
|
|
230
|
-
if (matches.length === 0) {
|
|
231
|
-
return {
|
|
232
|
-
kind: "no_match",
|
|
233
|
-
query,
|
|
234
|
-
snapshot: buildSearchSnapshot(query, messages),
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
return {
|
|
238
|
-
kind: "ok",
|
|
239
|
-
query,
|
|
240
|
-
snapshot: buildSearchSnapshot(query, messages, false),
|
|
241
|
-
matches,
|
|
242
|
-
};
|
|
243
|
-
}
|